|
From: Vibhu M. <vi...@ho...> - 2022-09-25 01:40:44
Attachments:
lispbibl.c.diff
|
Hi,
I've found and fixed a problem in lispbibl.d. I've attached an
indicative diff of the C file.
System: Windows 10, a fresh Cygwin, and the latest GitLab clisp.
I followed the instructions in INSTALL.windows ("3. Binaries for the
Cygwin environment"), for 64-bit binaries. Besides the prescribed
configure options, I added --ignore-absence-of-libsigsegv.
Make fails to produce spvw.o because lispbibl.c does this near line 1900:
#define CR 13
and then #includes a file (unix.c) that ultimate #includes
/usr/include/w32api/winnt.h
which itself has a legitimate symbol (not macro) named CR that gets
replaced by 13 resulting in a syntax error.
My fix is to move the whole #define block a few lines down to after the
#include block. That prevents the #define macros from inadvertently
capturing symbols from the included files.
----
I'm not an expert C programmer, but this technique of #including a file
after #defining a macro seems wrong in general. It makes changing the
included file impossibly hard as its author isn't free to use any new
symbols without fearing that an includer like clisp will capture them.
If clisp files followed a rule of never allowing #includes to follow
#defines, but to only ever precede them, I think that would consistently
prevent this particular sort of variable capture regardless of the depth
of an include hierarchy. An alternative prevention would be if include
file authors only created symbols with some namespace prefix, though
that would make their code unreadable.
With best wishes,
Vibhu |
|
From: Bruno H. <br...@cl...> - 2022-09-25 02:54:21
|
Vibhu Mohindra wrote:
> I've found and fixed a problem in lispbibl.d. I've attached an
> indicative diff of the C file.
>
> System: Windows 10, a fresh Cygwin, and the latest GitLab clisp.
>
> I followed the instructions in INSTALL.windows ("3. Binaries for the
> Cygwin environment"), for 64-bit binaries. Besides the prescribed
> configure options, I added --ignore-absence-of-libsigsegv.
>
> Make fails to produce spvw.o because lispbibl.c does this near line 1900:
> #define CR 13
> and then #includes a file (unix.c) that ultimate #includes
> /usr/include/w32api/winnt.h
> which itself has a legitimate symbol (not macro) named CR that gets
> replaced by 13 resulting in a syntax error.
Thanks for reporting this.
> My fix is to move the whole #define block a few lines down to after the
> #include block. That prevents the #define macros from inadvertently
> capturing symbols from the included files.
I think a less intrusive fix would be this one:
diff --git a/src/unix.d b/src/unix.d
index c600b6cbb..f82b9f157 100644
--- a/src/unix.d
+++ b/src/unix.d
@@ -566,7 +566,10 @@ extern int wait2 (pid_t pid); /* see unixaux.d */
#define WIN32_LEAN_AND_MEAN
#pragma push_macro ("Handle")
#undef Handle
+ #pragma push_macro ("CR")
+ #undef CR
#include <windows.h>
+ #pragma pop_macro ("CR")
#pragma pop_macro ("Handle")
#undef WIN32
extern long time_t_from_filetime (const FILETIME * ptr);
Can you please try it out?
> ----
> I'm not an expert C programmer, but this technique of #including a file
> after #defining a macro seems wrong in general. It makes changing the
> included file impossibly hard as its author isn't free to use any new
> symbols without fearing that an includer like clisp will capture them.
> If clisp files followed a rule of never allowing #includes to follow
> #defines, but to only ever precede them, I think that would consistently
> prevent this particular sort of variable capture regardless of the depth
> of an include hierarchy.
Such a rule is too rigid, and gets in the way of building larger software.
Most importantly, for maintainable software, one should follow the principle
that pieces of code that are semantically related should be close together.
Putting the #includes in one place, the macros in a second place, the function
declarations in a third place, and the function definitions in a fourth place
tends to go against maintainability. (Early PASCAL was criticized for this:
constants had to be defined first, then the types, then the functions, and
finally the main program.)
It's better to not have this rule, and deal with the occasional (rare)
conflicts on a case-by-case basis.
> An alternative prevention would be if include
> file authors only created symbols with some namespace prefix, though
> that would make their code unreadable.
Yes. Unfortunatelty, namespaces are a feature of newer programming languages,
like C++ and Common Lisp itself, but not of C.
Bruno
|
|
From: Vibhu M. <vi...@ho...> - 2022-09-25 03:54:40
|
Hi Bruno,
On 25/09/2022 04:41, Bruno Haible wrote:
> Vibhu Mohindra wrote:
>> My fix is to move the whole #define block a few lines down to after the
>> #include block. That prevents the #define macros from inadvertently
>> capturing symbols from the included files.
>
> I think a less intrusive fix would be this one:
>
> diff --git a/src/unix.d b/src/unix.d
> index c600b6cbb..f82b9f157 100644
> --- a/src/unix.d
> +++ b/src/unix.d
> @@ -566,7 +566,10 @@ extern int wait2 (pid_t pid); /* see unixaux.d */
> #define WIN32_LEAN_AND_MEAN
> #pragma push_macro ("Handle")
> #undef Handle
> + #pragma push_macro ("CR")
> + #undef CR
> #include <windows.h>
> + #pragma pop_macro ("CR")
> #pragma pop_macro ("Handle")
> #undef WIN32
> extern long time_t_from_filetime (const FILETIME * ptr);
>
> Can you please try it out?
Tried your fix instead of mine. Worked perfectly.
[Separate matter:
As before "make check" reports exactly one failure due to trying to open
/etc/passwd, which Cygwin doesn't have. I can't think of a file that's
definitely available on every platform, maybe /dev/zero or something or
even ./unix.c. This is tests/exceptsit.erg:
Form: (PROGN (OPEN "/etc/passwd" :DIRECTION :INPUT :IF-EXISTS :ERROR) (/ 0))
CORRECT: DIVISION-BY-ZERO
CLISP : #<SYSTEM::SIMPLE-FILE-ERROR #x00000008000A1D59>
]
>> ----
>> I'm not an expert C programmer, but this technique of #including a file
>> after #defining a macro seems wrong in general. It makes changing the
>> included file impossibly hard as its author isn't free to use any new
>> symbols without fearing that an includer like clisp will capture them.
>> If clisp files followed a rule of never allowing #includes to follow
>> #defines, but to only ever precede them, I think that would consistently
>> prevent this particular sort of variable capture regardless of the depth
>> of an include hierarchy.
>
> Such a rule is too rigid, and gets in the way of building larger software.
> Most importantly, for maintainable software, one should follow the principle
> that pieces of code that are semantically related should be close together.
> Putting the #includes in one place, the macros in a second place, the function
> declarations in a third place, and the function definitions in a fourth place
> tends to go against maintainability. (Early PASCAL was criticized for this:
> constants had to be defined first, then the types, then the functions, and
> finally the main program.)
>
> It's better to not have this rule, and deal with the occasional (rare)
> conflicts on a case-by-case basis.
I see. So this isn't a new kind of problem. Everyone's obviously seen it
before, and invented this macro pushing/popping. Cool stuff. Thanks for
explaining.
>> An alternative prevention would be if include
>> file authors only created symbols with some namespace prefix, though
>> that would make their code unreadable.
>
> Yes. Unfortunatelty, namespaces are a feature of newer programming languages,
> like C++ and Common Lisp itself, but not of C.
Oh right, I just meant namespaces the hard way: E.g. winnt.h would use
_WINNT_CR rather than bare CR. But in any case, it would mean the whole
world would have to agree on the convention before it could be useful,
and it would look ugly anyway. Not as practical as the PASCAL or
push/pop techniques.
Thanks a lot,
Vibhu
|
|
From: Bruno H. <br...@cl...> - 2022-09-25 10:51:57
|
Vibhu Mohindra wrote: > > Can you please try it out? > > Tried your fix instead of mine. Worked perfectly. Thank you for the quick return. I have now pushed the fix. > [Separate matter: > As before "make check" reports exactly one failure due to trying to open > /etc/passwd, which Cygwin doesn't have. I can't think of a file that's > definitely available on every platform, maybe /dev/zero or something or > even ./unix.c. This is tests/exceptsit.erg: > Form: (PROGN (OPEN "/etc/passwd" :DIRECTION :INPUT :IF-EXISTS :ERROR) (/ 0)) > CORRECT: DIVISION-BY-ZERO > CLISP : #<SYSTEM::SIMPLE-FILE-ERROR #x00000008000A1D59> > ] Since you have checked that this file does not exist on your system, you can obviously ignore the error. You're right that this file usually does not exist any more on Cygwin: <https://stackoverflow.com/questions/28573763>. Bruno |