The routine skip_empty_lines_and_read_char() is an optimization to skip over
blocks of comment lines. When it reads an unescaped '#' it uses the helper
routine skip_to_end_of_line(). But skip_to_end_of_line() doesn't fold lines
as it should and like its parent caller does. (See patch at end of message.)

I found this bug perusing the BearSSL source code.

  25 # The lines below are a horrible hack that nonetheless works. On a
  26 # "make" utility compatible with Single Unix v4 (this includes GNU and
  27 # BSD make), the '\' at the end of a command line counts as an escape
  28 # for the newline character, so the next line is still a comment.
  29 # However, Microsoft's nmake.exe (that comes with Visual Studio) does
  30 # not interpret the final '\' that way in a comment. The end result is
  31 # that when using nmake.exe, this will include "mk/Win.mk", whereas
  32 # GNU/BSD make will include "mk/Unix.mk".
  33 
  34 # \
  35 !ifndef 0 # \
  36 !include mk/NMake.mk # \
  37 !else
  38 .POSIX:
  39 include mk/SingleUnix.mk
  40 # Extra hack for OpenBSD make.
  41 ifndef: all
  42 0: all
  43 endif: all
  44 # \
  45 !endif

  -- https://bearssl.org/gitweb/?p=BearSSL;a=blob;f=Makefile;hb=9dc62112

It's definitely a bug. POSIX says,

  There are three kinds of comments: blank lines, empty lines, and a
  <number-sign> ( '#' ) and all following characters up to the first
  unescaped <newline> character.

and

  When an escaped <newline> (one preceded by a <backslash>) is found
  anywhere in the makefile except in a command line, an include line, or a
  line immediately preceding an include line, it shall be replaced, along
  with any leading white space on the following line, with a single <space>.

Fortunately POSIX leaves unspecified what happens to an escaped newline
preceding an include line. My patch should be the end of the
matter unless there's some other bug lurking. Here's a test case,

  # \
  broken:;@echo broken
  fixed:;@echo fixed

and the patch,

Index: lowparse.c
===================================================================
RCS file: /cvs/src/usr.bin/make/lowparse.c,v
retrieving revision 1.35
diff -u -r1.35 lowparse.c
--- lowparse.c  21 Oct 2016 16:12:38 -0000      1.35
+++ lowparse.c  23 Feb 2018 20:02:59 -0000
@@ -247,20 +247,21 @@
 static int
 skip_to_end_of_line(void)
 {
-       if (current->F) {
-               if (current->end - current->ptr > 1)
-                       current->ptr = current->end - 1;
-               if (*current->ptr == '\n')
-                       return *current->ptr++;
-               return EOF;
-       } else {
-               int c;
+       int escaped = 0, c;
 
-               do {
-                       c = read_char();
-               } while (c != '\n' && c != EOF);
-               return c;
+       while (EOF != (c = read_char())) {
+               if (escaped) {
+                       if (c == '\n')
+                               current->origin.lineno++;
+                       escaped = 0;
+               } else if (c == '\\') {
+                       escaped = 1;
+               } else if (c == '\n') {
+                       break;
+               }
        }
+
+       return c;
 }
 
 

Reply via email to