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

C macro identifiers (e.g. errno) are not properly avoided in code generation #11153

Closed
yglukhov opened this issue May 1, 2019 · 3 comments

Comments

Projects
None yet
5 participants
@yglukhov
Copy link
Member

commented May 1, 2019

The following code

proc foo(errno: int) =
  bar(errno)

Gets compiled into

N_LIB_PRIVATE N_NIMCALL(void, foo_h1iUOJW8XIEOh7Wb29bUPCg)(NI errno) {
        bar_ElecLSkU3MHVrwkSLbvxoQ(errno);
}

Given that some libc libraries define errno as (*_errno()), after c preprocessor we end up with smth like

N_LIB_PRIVATE N_NIMCALL(void, foo_h1iUOJW8XIEOh7Wb29bUPCg)(NI (*_errno())) {
        bar_ElecLSkU3MHVrwkSLbvxoQ((*_errno()));
}

Basically the code foo(5) will try to call a function with address 5.

The suggestion is to reintroduce special mangling rules (for a list of symbols like errno, far, near, etc) in the backend instead of the #unset approach as it is done now.

@Araq

This comment has been minimized.

Copy link
Member

commented May 2, 2019

We have a general mechanism for this in the compiler but I forgot its name :P

@Araq Araq added the High Priority label May 2, 2019

@krux02

This comment has been minimized.

Copy link
Contributor

commented May 2, 2019

There is not just errno that might cause conflics. I think it would be wise to register all preprocessor defines. For gcc there is a way to get a list of all preprocessor defines:

gcc -dM -E /tmp/test.h | grep -v '\#define __'

relevent gcc man page section:

       -E  Stop after the preprocessing stage; do not run the compiler proper.  The output is in the form of preprocessed source code, which is sent to the standard
           output.

[...]

           -dM Instead of the normal output, generate a list of #define directives for all the macros defined during the execution of the preprocessor, including
               predefined macros.  This gives you a way of finding out what is predefined in your version of the preprocessor.  Assuming you have no file foo.h, the
               command

                       touch foo.h; cpp -dM foo.h

               shows all the predefined macros.

               If you use -dM without the -E option, -dM is interpreted as a synonym for -fdump-rtl-mach.

test.h

#define version 123
#include <errno.h>
output
#define EMULTIHOP 72
#define EUNATCH 49
#define EAFNOSUPPORT 97
#define EREMCHG 78
#define EACCES 13
#define EDESTADDRREQ 89
#define EILSEQ 84
#define ESPIPE 29
#define EMLINK 31
#define EOWNERDEAD 130
#define _ASM_GENERIC_ERRNO_BASE_H 
#define ENOTTY 25
#define _BITS_ERRNO_H 1
#define EBADE 52
#define EBADF 9
#define EBADR 53
#define EADV 68
#define ERANGE 34
#define ECANCELED 125
#define ETXTBSY 26
#define ENOMEM 12
#define _ERRNO_H 1
#define EINPROGRESS 115
#define _ATFILE_SOURCE 1
#define ENOTBLK 15
#define EPROTOTYPE 91
#define ERESTART 85
#define EISNAM 120
#define ENOMSG 42
#define EALREADY 114
#define _POSIX_SOURCE 1
#define _DEFAULT_SOURCE 1
#define ETIMEDOUT 110
#define ENODATA 61
#define EINTR 4
#define ENOLINK 67
#define EPERM 1
#define ELOOP 40
#define ENETDOWN 100
#define ESTALE 116
#define ENOSR 63
#define ELNRNG 48
#define EPIPE 32
#define ECHILD 10
#define EBADMSG 74
#define _FEATURES_H 1
#define EBFONT 59
#define EREMOTE 66
#define ETOOMANYREFS 109
#define ENONET 64
#define EXFULL 54
#define ENOTEMPTY 39
#define ENOTNAM 118
#define EKEYREJECTED 129
#define ENOCSI 50
#define EADDRINUSE 98
#define ENETRESET 102
#define EISDIR 21
#define EIDRM 43
#define _SYS_CDEFS_H 1
#define _STDC_PREDEF_H 1
#define ENOTSOCK 88
#define EHOSTUNREACH 113
#define EBADFD 77
#define EL3HLT 46
#define EL2HLT 51
#define ENOKEY 126
#define EINVAL 22
#define unix 1
#define ESHUTDOWN 108
#define ENOMEDIUM 123
#define ELIBSCN 81
#define _POSIX_C_SOURCE 200809L
#define ENAVAIL 119
#define EOVERFLOW 75
#define EUCLEAN 117
#define EBUSY 16
#define EPROTO 71
#define ENODEV 19
#define EKEYEXPIRED 127
#define EROFS 30
#define ELIBACC 79
#define EHWPOISON 133
#define E2BIG 7
#define EDEADLK 35
#define EL3RST 47
#define ENOTDIR 20
#define ECONNRESET 104
#define linux 1
#define ENXIO 6
#define EBADRQC 56
#define ENOSTR 60
#define ENAMETOOLONG 36
#define version 123
#define ESOCKTNOSUPPORT 94
#define ELIBEXEC 83
#define EDOTDOT 73
#define EADDRNOTAVAIL 99
#define ETIME 62
#define EPROTONOSUPPORT 93
#define ENOTRECOVERABLE 131
#define EIO 5
#define ENETUNREACH 101
#define EXDEV 18
#define EDQUOT 122
#define EREMOTEIO 121
#define ENOSPC 28
#define ENOEXEC 8
#define EMSGSIZE 90
#define EDOM 33
#define _LP64 1
#define EFBIG 27
#define ESRCH 3
#define ECHRNG 44
#define EHOSTDOWN 112
#define ENOLCK 37
#define ENFILE 23
#define ENOSYS 38
#define ENOTCONN 107
#define EPFNOSUPPORT 96
#define ENOTSUP EOPNOTSUPP
#define ESRMNT 69
#define EDEADLOCK EDEADLK
#define ECONNABORTED 103
#define ENOANO 55
#define EISCONN 106
#define EUSERS 87
#define ENOPROTOOPT 92
#define ECOMM 70
#define EMFILE 24
#define ERFKILL 132
#define ENOBUFS 105
#define EFAULT 14
#define EWOULDBLOCK EAGAIN
#define ELIBBAD 80
#define ESTRPIPE 86
#define ECONNREFUSED 111
#define _ASM_GENERIC_ERRNO_H 
#define EAGAIN 11
#define ELIBMAX 82
#define EEXIST 17
#define errno (*__errno_location ())
#define EL2NSYNC 45
#define ENOENT 2
#define ENOPKG 65
#define EBADSLT 57
#define EKEYREVOKED 128
#define ENOTUNIQ 76
#define EOPNOTSUPP 95
#define EMEDIUMTYPE 124

I've filtered with grep -v '\#define __', as identifires starting with __ are reserverd for compiler internal identifiers anyway. With the following command line the defines are reduced to names only.

gcc -dM -E /tmp/test.h | grep -v '\#define __' | sed 's/^\#define \([^ ]*\).*$/\1/'

I just don't know what to do with compilers that don't support this introspection. At least when symbols are explicitly imported already, nim does not create conflicting identifiers anymore.

var errno* {.importc: "errno", header: "<errno.h>".}: int
echo errno

proc bar(arg: int) =
  discard

proc foo(errno: int) =
  bar(errno)

foo(5)

generated C code

N_LIB_PRIVATE N_NIMCALL(void, foo_mojuEClTeBwWoZtfMTgRlg)(NI errno_0);

@krux02 krux02 changed the title errno is not mangled C macro identifiers (e.g. errno) are not properly avoided in code generation May 2, 2019

@Araq Araq closed this in 3a479ff May 10, 2019

@nc-x

This comment has been minimized.

Copy link
Contributor

commented May 10, 2019

@Araq This fix is probably affected by #9575

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.