Skip to content
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

Name collision in ctypegen? #146

Open
abstractor84 opened this issue Jun 2, 2022 · 3 comments
Open

Name collision in ctypegen? #146

abstractor84 opened this issue Jun 2, 2022 · 3 comments

Comments

@abstractor84
Copy link

I have a simple C file and Header File. Where the header has 2 typedef structures and one function, where the function accepts a struct pointer parameter, this parameter can be any name as per C99 (I believe ctypesgen is based on this standard). However ctypesgen fails to parse this properly, and failed to construct an equivalent python code as this name is already used to refer another structure (alias first_struct).

Is there any workaround or fix for this issue? (The actual issue was with a large C code base, which i reproduced with this simple files)

So far, i'm able to proceed, if i change the function parameter name from some_struct to other names like some_struct_param), But I can't change the original C files as its from a 3rd party, and needs to be shipped as is.

Appreciate any help.

Failure: ERROR: /home/test.h:12: Syntax error at 'some_struct'

Env details (reported here):
Python: Python 3.9.2
ctypegen: 1.0.2
OS: debian11
gcc: gcc12

Note: Also tested on a centos7 machine; with Python: 3.6.8, ctypesgen: 1.0.2, gcc: 4.8.5, The result is same.

My Header file:

//test.h
typedef struct {
        int x;
} first_struct, some_struct;

typedef struct {
        int a;
        char c;
} MyStruct;

//MyStruct some_struct;

void test_api(MyStruct *some_struct);

My C prog:

//test.c
#include <stdio.h>
#include "test.h"

int main() {
        MyStruct test1;
        test1.a = 10;
        printf("initial value in main func is %d\n", test1.a);
        test_api(&test1);
        printf("value in main func: %d\n", test1.a);
        return 0;
}

void test_api(MyStruct *struct_arg) {
        printf("Inside test_api\n");
        printf("Value now is: %d\n", struct_arg->a);
        struct_arg->a = 33;
        printf("Value now is: %d\n", struct_arg->a);
}

When running ctypesgen with below arguments, I think I'm getting a name collision in python, so its reporting a syntax error, however as per C99 & gnu99 this is perfectly valid, and in C it works flawlessly.

Here is the output of 1) C prog compilation, 2) C prog execution, 3) C prog pre-processing, 4) ctypesgen output.
1) C prog compilation

bash~# gcc -Wall  -std=gnu90 -I./ ./test.c  -o test_bin
bash~# echo $?
0
bash~# 

2) C prog execution

bash~# ./test_bin
initial value in main func is 10
Inside test_api
Value now is: 10
Value now is: 33
value in main func: 33
bash~#

3) C prog pre-processing
Output too large to attach, however there is no errors reported, will upload it as a file.

4) Generating shared lib

bash~# gcc -Wall -fPIC -std=gnu90 -I./ ./test.c -shared  -o test.so
bash~# 

4) ctypesgen output.

bash~# ctypesgen --cpp='gcc -E -std=gnu90' -l test.so ./test.h -o /tmp/out  --save-preprocessed-headers=/tmp/pre-out
INFO: Status: Preprocessing /tmp/tmpxiy8gi92.h
INFO: Status: gcc -E -std=gnu90 -U __GNUC__ -dD "-Dinline=" "-D__inline__=" "-D__extension__=" "-D__const=const" "-D__asm__(x)=" "-D__asm(x)=" "-DCTYPESGEN=1" "/tmp/tmpxiy8gi92.h"
INFO: Status: Saving preprocessed headers to /tmp/pre-out.
INFO: Status: Parsing /tmp/tmpxiy8gi92.h
ERROR: /home/test.h:12: Syntax error at 'some_struct'
INFO: Status: Processing description list.
INFO: Status: Writing to /tmp/out.
INFO: Status: Wrapping complete.
bash~#
@abstractor84
Copy link
Author

Adding other required details related to this issue;

C pre processing output: https://pastebin.com/pPMtQmcc
ctypesgen pre-processed headers: pre-out.txt
ctypesgen output python file: out.py.txt

@nilason
Copy link
Collaborator

nilason commented May 23, 2023

@abstractor84 Thanks for an exemplary report! Sorry for replying only now.

I'll see what can be done to fix this. Note, it would have worked with unnamed parameter in the prototype:

// test.h
void test_api(MyStruct *);
// test.c
void test_api(MyStruct *struct_arg) {

@mara004
Copy link
Contributor

mara004 commented Dec 16, 2023

Note, it would have worked with unnamed parameter in the prototype:

Not only with unnamed parameter, but also with any other non-colliding name I think.
Note that, in the example, there's a name mismatch between the .h and the .c file: some_struct vs struct_arg.1
It should work if we use struct_arg also in the .h.

However, when changing struct_arg to some_struct in the C file, it still compiles (i.e. type shadowing seems to be allowed), so the issue still stands.
That said, Python also allows shadowing, and the parameter name would never land in the output anyway (only types), so "name collision in python" is a bit confusing. "name collision in ctypesgen's parser" might be more precise.
It seems like the parser currently checks param names, but I guess it could just ignore them?


That said, I think the OP is already aware of the renaming approach

So far, i'm able to proceed, if i change the function parameter name from some_struct to other names like some_struct_param), But I can't change the original C files as its from a 3rd party, and needs to be shipped as is.

I don't think name shadowing is good practice, albeit allowed. The 3rd party may be happy to take a patch, leastways if it's open source. Also it shouldn't be a big deal to feed a patched copy of headers into ctypesgen, seeing as the param name does not affect the output, just the parsing.

Footnotes

  1. I believe this is discouraged, analyzers might complain

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants