admin管理员组文章数量:1333632
I need to execute some python and C at the same time. I tried using Python.h:
#include <Python.h>
int python_program(char* cwd)
{
char* python_file_path;
FILE* fd;
int run;
python_file_path = malloc(sizeof(char) * (strlen(cwd) + strlen("src/query.py") + 1));
strcpy(python_file_path, cwd);
strcat(python_file_path, "src/query.py");
fd = fopen(python_file_path, "r");
Py_Initialize();
run = PyRun_AnyFile(fd, "query.py"); //this part is where the bug occur i think
Py_Finalize();
free(python_file_path);
}
int main(int argc, char *argv[])
{
char cwd_buffer[64];
getcwd(cwd_buffer, sizeof(cwd_buffer));
python_program(cwd_buffer);
return 0;
}
...but there's an error with segmentation fault.
26057 segmentation fault (core dumped) ../spotify-viewer-cli
I isolated the Python.h part and it's the problem. So how can I execute the python file in my C program?
I need to execute some python and C at the same time. I tried using Python.h:
#include <Python.h>
int python_program(char* cwd)
{
char* python_file_path;
FILE* fd;
int run;
python_file_path = malloc(sizeof(char) * (strlen(cwd) + strlen("src/query.py") + 1));
strcpy(python_file_path, cwd);
strcat(python_file_path, "src/query.py");
fd = fopen(python_file_path, "r");
Py_Initialize();
run = PyRun_AnyFile(fd, "query.py"); //this part is where the bug occur i think
Py_Finalize();
free(python_file_path);
}
int main(int argc, char *argv[])
{
char cwd_buffer[64];
getcwd(cwd_buffer, sizeof(cwd_buffer));
python_program(cwd_buffer);
return 0;
}
...but there's an error with segmentation fault.
26057 segmentation fault (core dumped) ../spotify-viewer-cli
I isolated the Python.h part and it's the problem. So how can I execute the python file in my C program?
Share Improve this question edited Nov 20, 2024 at 16:41 genpfault 52.2k12 gold badges91 silver badges149 bronze badges asked Nov 20, 2024 at 16:37 YukiYuki 931 silver badge5 bronze badges 4 |5 Answers
Reset to default 0Golden rule: error handling is not an option but a hard requirement in programming (pointed out by answers and comments).
Failing to include it might work for a while, but almost certainly will come back and bite in the ass at a later time, and it will do it so hard that someone (unfortunately, often not the same person who wrote the faulty code) will spend much more time (than writing it in the 1st place) fixing subtle errors (or crashes).
Also, reading the documentation for the used functions, might save precious time too, avoiding all kinds of errors generated by passing to them arguments based on some false assumptions.
Same case here (Undefined Behavior):
[Man7]: getcwd(3) doesn't end the path with a separator (/)
Computed script path doesn't exist
fopen fails (returns NULL)
- PyRun_AnyFile SegFaults
I created a MCVE ([SO]: How to create a Minimal, Reproducible Example (reprex (mcve))), and also added some printf statements useful to identify the culprit (the preferred option would be to go step by step using a debugger (e.g.: [SourceWare]: GDB: The GNU Project Debugger)).
dir00/code00.py
#!/usr/bin/env python import os import sys def main(*argv): print(f"From Python - file: {os.path.abspath(__file__)}") if __name__ == "__main__": print( "Python {:s} {:03d}bit on {:s}\n".format( " ".join(elem.strip() for elem in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform, ) ) rc = main(*sys.argv[1:]) #print("\nDone.\n") #sys.exit(rc)
main00.c:
#include <errno.h> #include <stdio.h> #include <unistd.h> #include <Python.h> #define PY_SCRIPT "code00.py" #define FULL_PY_SCRIPT "dir00/" PY_SCRIPT int runPyFile(const char *wd) { char *script; FILE *fp; int res; script = malloc(sizeof(char) * (strlen(wd) + strlen(FULL_PY_SCRIPT) + 2)); if (!script) { printf("malloc error: %d\n", errno); return -1; } strcpy(script, wd); strcat(script, "/"); // @TODO - cfati strcat(script, FULL_PY_SCRIPT); printf("script path: %s\n", script); if (access(script, F_OK)) { // Extra check printf("Script doesn't exist\n"); return -2; } fp = fopen(script, "r"); if (!fp) { printf("fopen error: %d\n", errno); free(script); return -3; } free(script); Py_Initialize(); res = PyRun_SimpleFile(fp, PY_SCRIPT); // Call this function directly (skip PyRun_AnyFile layer) if (res) { printf("PyRun_SimpleFile error\n"); } Py_Finalize(); fclose(fp); return res; } int main(int argc, char *argv[]) { char cwd[PATH_MAX]; if (!getcwd(cwd, sizeof(cwd))) { printf("getcwd error: %d\n", errno); return -1; } printf("cwd (check its end): %s\n", cwd); int res = runPyFile(cwd); if (res) { // Some extra handling (or exit function if it's more complex) } else { printf("Script ran fine\n"); } printf("\nDone.\n\n"); return res; }
Output:
[cfati@cfati-5510-0:/mnt/e/Work/Dev/StackExchange/StackOverflow/q079208182]> ~/sopr.sh ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [064bit prompt]> tree . +-- dir00 ¦ +-- code00.py +-- main00.c 1 directory, 2 files [064bit prompt]> [064bit prompt]> PY_VER="3.11" [064bit prompt]> gcc -fPIC -I/usr/include/python${PY_VER} -o test${PY_VER} -L/usr/lib/$(uname -m)-linux-gnu main00.c -lpython${PY_VER} [064bit prompt]> ls dir00 main00.c test3.11 [064bit prompt]> [064bit prompt]> ./test${PY_VER} cwd (check its end): /mnt/e/Work/Dev/StackExchange/StackOverflow/q079208182 script path: /mnt/e/Work/Dev/StackExchange/StackOverflow/q079208182/dir00/code00.py Python 3.11.3 (main, Apr 5 2023, 14:15:06) [GCC 9.4.0] 064bit on linux From Python - file: /mnt/e/Work/Dev/StackExchange/StackOverflow/q079208182/code00.py Script ran fine Done.
I tried using Python.h (maybe it's not the most performant solution).
Python.h
is one detail -- and not even the most important -- of embedding a Python interpreter inside your C program. "Using Python.h" is not a great way of describing that. However, embedding Python in your C program is generally a pretty performant way to run Python code.
Your general approach looks ok, but there are some issues with the details. Very likely you would detect a problem earlier on, and more manageably, if your code actually looked, as any robust C program must do. Potential issues include:
main()
'scwd_buffer
might not be large enough to hold an absolute path to the current working directory. In that case,getcwd()
would fail, returning a null pointer and settingerrno
toENAMETOOLONG
. You would detect this by verifying that the return value is not null.getcwd()
might also fail for a variety of other, less likely reasons, which again you would detect by checking whether a null pointer was returned.python_program()
's call tomalloc()
might fail, returning a null pointer and settingerrno
appropriately. You would detect this by verifying that the return value is not null.The code
strcpy(python_file_path, cwd); strcat(python_file_path, "src/query.py");
might not -- and probably does not -- construct a correct path to the Python file. It would almost certainly be incorrect if
cwd
did not contain a trailing slash character, and I expect that it will not. Although you cannot detect such an issue directly, see next.You do not check whether opening the Python file succeeds, which it probably won't on account of the previous issue. If opening it fails for that or any of the other possible reasons, then
fopen()
will fail, returning a null pointer and settingerrno
appropriately. You would detect this by checking whether the return value is null. If your program reaches the call toPyRun_AnyFile()
and the segfault is thrown there, then having failed to open the file is a likely explanation.
Add check to see if you pass the correct fd
fd = fopen(python_file_path, "r");
if(!fd)
{
printf("Cant open '%s'\n", python_file_path);
/* handle this error - abort return or something else */
}
It looks like you're running on a *nix system so you're missing a "/"
in strcat(python_file_path, "src/query.py");
line to separate cwd
from /src/query.py. It should be:
strcat(python_file_path, "/src/query.py");
Without it the name of the Python script to run is:
/home/user/c-code/segfault-pythonsrc/query.py
while it should be:
/home/user/c-code/segfault-python/src/query.py
You would know that BTW if you checked value of fd
as suggested in other
answers. You should also reserve a space for it while mallocing:
python_file_path = malloc(sizeof(char) * (strlen(cwd) + strlen("/src/query.py") + 1));
I didn't need the Python.h library, what i did is using system() in the sys/ library. I used named pipes for transmitting data between programs.
本文标签: Segmentation fault when executing a Python script in a C programStack Overflow
版权声明:本文标题:Segmentation fault when executing a Python script in a C program? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742343859a2457127.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
fopen
. – G.M. Commented Nov 20, 2024 at 16:40python_program()
. Start from fixing simple mistakes, compile withcc main.c -o main -Wall -Wextra -pedantic
and then if there are no errors any more compile with-g
and run your binary under valgrind to identify the line that triggers segfault. – Arkadiusz Drabczyk Commented Nov 20, 2024 at 16:51fopen()
will indeed return NULL; Debug the filenamepython_file_path
:-) – Ingo Leonhardt Commented Nov 20, 2024 at 17:04