[HarfBuzz] harfbuzz: Branch 'master' - 5 commits

Behdad Esfahbod behdad at kemper.freedesktop.org
Tue Jun 26 18:44:22 UTC 2018


 .circleci/config.yml                                                            |    6 
 src/hb-blob.cc                                                                  |  152 ++++------
 test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5750092395970560 |binary
 test/subset/run-tests.py                                                        |  101 +++---
 util/options.cc                                                                 |   27 -
 5 files changed, 134 insertions(+), 152 deletions(-)

New commits:
commit 7db2e9ea38329b9393c9e8cc905b180735c9b0f4
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Tue Jun 26 10:46:10 2018 +0430

    Minor on hb_blob_create_from_file
    
    Add one more "unlikely" annotation and use explicit nullptr check for more consistency.

diff --git a/src/hb-blob.cc b/src/hb-blob.cc
index 37a6d8cb..155c2e6b 100644
--- a/src/hb-blob.cc
+++ b/src/hb-blob.cc
@@ -597,7 +597,7 @@ fail_without_close:
   int len = 0;
   int allocated = BUFSIZ * 16;
   char *blob = (char *) malloc (allocated);
-  if (blob == nullptr) return hb_blob_get_empty ();
+  if (unlikely (blob == nullptr)) return hb_blob_get_empty ();
 
   FILE *fp = fopen (file_name, "rb");
   if (unlikely (fp == nullptr)) goto fread_fail_without_close;
@@ -611,7 +611,7 @@ fail_without_close:
       // can cover files like that but lets limit our fallback reader
       if (unlikely (allocated > 200000000)) goto fread_fail;
       char *new_blob = (char *) realloc (blob, allocated);
-      if (unlikely (!new_blob)) goto fread_fail;
+      if (unlikely (new_blob == nullptr)) goto fread_fail;
       blob = new_blob;
     }
 
commit 4f8753464ae44dfb60bee81ede10448175db7b90
Author: Garret Rieger <grieger at google.com>
Date:   Fri Jun 22 15:29:34 2018 -0700

    [subset] Add fuzzer test case that caused a timeout to the corpus.

diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5750092395970560 b/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5750092395970560
new file mode 100644
index 00000000..d622c256
Binary files /dev/null and b/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5750092395970560 differ
commit 35ce8f31d37cf7c2a1f8265d36ba4c2c9a3efb2c
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Mon Jun 25 22:23:43 2018 +0430

    Unify our pipe reader with the fallback reader (#1068)
    
    And assign one bot to use the path always using NOMMAPFILEREADER token.
    
    It's limited to 200mb so no more fun with using /dev/zero on hb-view!

diff --git a/.circleci/config.yml b/.circleci/config.yml
index 55820005..de130b50 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -40,14 +40,14 @@ jobs:
       - run: rm -rf harfbuzz-*
       - run: make distdir && cd harfbuzz-* && cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test && ninja -Cbuild install
 
-  alpine-O3:
+  alpine-O3-NOMMAP:
     docker:
       - image: alpine
     steps:
       - checkout
       - run: apk update && apk add ragel make pkgconfig libtool autoconf automake gettext gcc g++ glib-dev freetype-dev cairo-dev
       # C??FLAGS are not needed for a regular build
-      - run: CFLAGS="-O3" CXXFLAGS="-O3" ./autogen.sh
+      - run: CFLAGS="-O3" CXXFLAGS="-O3 -DNOMMAPFILEREADER" ./autogen.sh
       - run: make
       - run: make check || .ci/fail.sh
 
@@ -196,7 +196,7 @@ workflows:
       - distcheck
 
       # autotools based builds
-      - alpine-O3
+      - alpine-O3-NOMMAP
       - archlinux-debug-O0-py3
       - clang-O3-O0
       - fedora-outoftreebuild
diff --git a/src/hb-blob.cc b/src/hb-blob.cc
index 77dbc715..37a6d8cb 100644
--- a/src/hb-blob.cc
+++ b/src/hb-blob.cc
@@ -499,36 +499,6 @@ hb_blob_t::try_make_writable (void)
 # define MAP_NORESERVE 0
 #endif
 
-static hb_blob_t *
-_fread_to_end (FILE *file)
-{
-  int allocated = BUFSIZ * 16;
-  char *blob = (char *) malloc (allocated);
-  if (blob == nullptr) return hb_blob_get_empty ();
-
-  int len = 0;
-  while (!feof (file))
-  {
-    if (allocated - len < BUFSIZ)
-    {
-      allocated *= 2;
-      char *new_blob = (char *) realloc (blob, allocated);
-      if (unlikely (!new_blob)) goto fail;
-      blob = new_blob;
-    }
-
-    len += fread (blob + len, 1, allocated - len, file);
-    if (ferror (file)) goto fail;
-  }
-
-  return hb_blob_create (blob, len, HB_MEMORY_MODE_WRITABLE, blob,
-			 (hb_destroy_func_t) free);
-
-fail:
-  free (blob);
-  return hb_blob_get_empty ();
-}
-
 struct hb_mapped_file_t
 {
   char *contents;
@@ -547,7 +517,7 @@ _hb_mapped_file_destroy (hb_mapped_file_t *file)
   UnmapViewOfFile (file->contents);
   CloseHandle (file->mapping);
 #else
-  free (file->contents);
+  assert (0); // If we don't have mmap we shouldn't reach here
 #endif
 
   free (file);
@@ -566,87 +536,95 @@ hb_blob_create_from_file (const char *file_name)
 {
   // Adopted from glib's gmappedfile.c with Matthias Clasen and
   // Allison Lortie permission but changed a lot to suit our need.
-  bool writable = false;
-  hb_memory_mode_t mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
+#if defined(HAVE_MMAP) && !defined(NOMMAPFILEREADER)
   hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
   if (unlikely (!file)) return hb_blob_get_empty ();
 
-#ifdef HAVE_MMAP
-  int fd = open (file_name, (writable ? O_RDWR : O_RDONLY) | _O_BINARY, 0);
-# define CLOSE close
+  int fd = open (file_name, O_RDONLY | _O_BINARY, 0);
   if (unlikely (fd == -1)) goto fail_without_close;
 
   struct stat st;
   if (unlikely (fstat (fd, &st) == -1)) goto fail;
 
-  // See https://github.com/GNOME/glib/blob/f9faac7/glib/gmappedfile.c#L139-L142
-  if (unlikely (st.st_size == 0 && S_ISREG (st.st_mode))) goto fail;
-
   file->length = (unsigned long) st.st_size;
-  file->contents = (char *) mmap (nullptr, file->length,
-				  writable ? PROT_READ|PROT_WRITE : PROT_READ,
+  file->contents = (char *) mmap (nullptr, file->length, PROT_READ,
 				  MAP_PRIVATE | MAP_NORESERVE, fd, 0);
 
-  if (unlikely (file->contents == MAP_FAILED))
-  {
-    free (file);
-    FILE *f = fdopen (fd, "rb");
-    if (unlikely (f == nullptr))
-    {
-      CLOSE (fd);
-      return hb_blob_get_empty ();
-    }
-    hb_blob_t *blob = _fread_to_end (f);
-    fclose (f);
-    return blob;
-  }
+  if (unlikely (file->contents == MAP_FAILED)) goto fail;
 
-#elif defined(_WIN32) || defined(__CYGWIN__)
-  HANDLE fd = CreateFile (file_name,
-			  writable ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ,
-			  FILE_SHARE_READ, nullptr, OPEN_EXISTING,
-			  FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr);
-# define CLOSE CloseHandle
+  close (fd);
+
+  return hb_blob_create (file->contents, file->length,
+			 HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
+			 (hb_destroy_func_t) _hb_mapped_file_destroy);
+
+fail:
+  close (fd);
+fail_without_close:
+  free (file);
+
+#elif (defined(_WIN32) || defined(__CYGWIN__)) && !defined(NOMMAPFILEREADER)
+  hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
+  if (unlikely (!file)) return hb_blob_get_empty ();
+
+  HANDLE fd = CreateFile (file_name, GENERIC_READ, FILE_SHARE_READ, nullptr,
+			  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
+			  nullptr);
 
   if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
 
   file->length = (unsigned long) GetFileSize (fd, nullptr);
-  file->mapping = CreateFileMapping (fd, nullptr,
-				     writable ? PAGE_WRITECOPY : PAGE_READONLY,
-				     0, 0, nullptr);
+  file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr);
   if (unlikely (file->mapping == nullptr)) goto fail;
 
-  file->contents = (char *) MapViewOfFile (file->mapping,
-					   writable ? FILE_MAP_COPY : FILE_MAP_READ,
-					   0, 0, 0);
+  file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);
   if (unlikely (file->contents == nullptr)) goto fail;
 
-#else
-  mm = HB_MEMORY_MODE_WRITABLE;
+  CloseHandle (fd);
+  return hb_blob_create (file->contents, file->length,
+			 HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
+			 (hb_destroy_func_t) _hb_mapped_file_destroy);
 
-  FILE *fd = fopen (file_name, "rb");
-# define CLOSE fclose
-  if (unlikely (!fd)) goto fail_without_close;
+fail:
+  CloseHandle (fd);
+fail_without_close:
+  free (file);
+
+#endif
+
+  // The following tries to read a file without knowing its size beforehand
+  // It's used for systems without mmap concept or to read from pipes
+  int len = 0;
+  int allocated = BUFSIZ * 16;
+  char *blob = (char *) malloc (allocated);
+  if (blob == nullptr) return hb_blob_get_empty ();
 
-  fseek (fd, 0, SEEK_END);
-  file->length = ftell (fd);
-  rewind (fd);
-  file->contents = (char *) malloc (file->length);
-  if (unlikely (!file->contents)) goto fail;
+  FILE *fp = fopen (file_name, "rb");
+  if (unlikely (fp == nullptr)) goto fread_fail_without_close;
 
-  if (unlikely (fread (file->contents, 1, file->length, fd) != file->length))
-    goto fail;
+  while (!feof (fp))
+  {
+    if (allocated - len < BUFSIZ)
+    {
+      allocated *= 2;
+      // Don't allocate more than 200MB, our mmap reader still
+      // can cover files like that but lets limit our fallback reader
+      if (unlikely (allocated > 200000000)) goto fread_fail;
+      char *new_blob = (char *) realloc (blob, allocated);
+      if (unlikely (!new_blob)) goto fread_fail;
+      blob = new_blob;
+    }
 
-#endif
+    len += fread (blob + len, 1, allocated - len, fp);
+    if (unlikely (ferror (fp))) goto fread_fail;
+  }
 
-  CLOSE (fd);
-  return hb_blob_create (file->contents, file->length, mm, (void *) file,
-			 (hb_destroy_func_t) _hb_mapped_file_destroy);
+  return hb_blob_create (blob, len, HB_MEMORY_MODE_WRITABLE, blob,
+                         (hb_destroy_func_t) free);
 
-fail:
-  CLOSE (fd);
-#undef CLOSE
-fail_without_close:
-  free (file);
+fread_fail:
+  fclose (fp);
+fread_fail_without_close:
+  free (blob);
   return hb_blob_get_empty ();
 }
commit f57804a8a596e88843ddc8b88afac7526349b89b
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Mon Jun 25 18:45:49 2018 +0430

    Resolve ttx absolute path before use (#1075)

diff --git a/test/subset/run-tests.py b/test/subset/run-tests.py
index 1cd1a19f..bc0d082e 100755
--- a/test/subset/run-tests.py
+++ b/test/subset/run-tests.py
@@ -15,75 +15,94 @@ import tempfile
 
 from subset_test_suite import SubsetTestSuite
 
+# https://stackoverflow.com/a/377028
+def which(program):
+	def is_exe(fpath):
+		return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+
+	fpath, _ = os.path.split(program)
+	if fpath:
+		if is_exe(program):
+			return program
+	else:
+		for path in os.environ["PATH"].split(os.pathsep):
+			exe_file = os.path.join(path, program)
+			if is_exe(exe_file):
+				return exe_file
+
+	return None
+
+ttx = which ("ttx")
+ots_sanitize = which ("ots-sanitize")
+
+if not ttx:
+	print("TTX is not present, skipping test.")
+	sys.exit (77)
 
 def cmd(command):
 	p = subprocess.Popen (
 		command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-	(stdoutdata, stderrdata) = p.communicate()
+	(stdoutdata, stderrdata) = p.communicate ()
 	print (stderrdata, end="") # file=sys.stderr
 	return stdoutdata, p.returncode
 
-def read_binary(file_path):
-	with open(file_path, 'rb') as f:
-		return f.read()
+def read_binary (file_path):
+	with open (file_path, 'rb') as f:
+		return f.read ()
 
 def fail_test(test, cli_args, message):
 	print ('ERROR: %s' % message)
 	print ('Test State:')
-	print ('  test.font_path    %s' % os.path.abspath(test.font_path))
-	print ('  test.profile_path %s' % os.path.abspath(test.profile_path))
-	print ('  test.unicodes	    %s' % test.unicodes())
-	expected_file = os.path.join(test_suite.get_output_directory(),
-				     test.get_font_name())
-	print ('  expected_file	    %s' % os.path.abspath(expected_file))
+	print ('  test.font_path    %s' % os.path.abspath (test.font_path))
+	print ('  test.profile_path %s' % os.path.abspath (test.profile_path))
+	print ('  test.unicodes	    %s' % test.unicodes ())
+	expected_file = os.path.join(test_suite.get_output_directory (),
+				     test.get_font_name ())
+	print ('  expected_file	    %s' % os.path.abspath (expected_file))
 	return 1
 
 def run_test(test, should_check_ots):
-	out_file = os.path.join(tempfile.mkdtemp(), test.get_font_name() + '-subset.ttf')
+	out_file = os.path.join(tempfile.mkdtemp (), test.get_font_name () + '-subset.ttf')
 	cli_args = [hb_subset,
 		    "--font-file=" + test.font_path,
 		    "--output-file=" + out_file,
-		    "--unicodes=%s" % test.unicodes()]
-	cli_args.extend (test.get_profile_flags())
-	print (' '.join(cli_args))
-	_, return_code = cmd(cli_args)
+		    "--unicodes=%s" % test.unicodes ()]
+	cli_args.extend (test.get_profile_flags ())
+	print (' '.join (cli_args))
+	_, return_code = cmd (cli_args)
 
 	if return_code:
-		return fail_test(test, cli_args, "%s returned %d" % (' '.join(cli_args), return_code))
+		return fail_test (test, cli_args, "%s returned %d" % (' '.join (cli_args), return_code))
 
-	expected_ttx, return_code = run_ttx(os.path.join(test_suite.get_output_directory(),
-					    test.get_font_name()))
+	expected_ttx, return_code = run_ttx (os.path.join (test_suite.get_output_directory (),
+					    test.get_font_name ()))
 	if return_code:
-		return fail_test(test, cli_args, "ttx (expected) returned %d" % (return_code))
+		return fail_test (test, cli_args, "ttx (expected) returned %d" % (return_code))
 
 	actual_ttx, return_code = run_ttx(out_file)
 	if return_code:
-		return fail_test(test, cli_args, "ttx (actual) returned %d" % (return_code))
+		return fail_test (test, cli_args, "ttx (actual) returned %d" % (return_code))
 
 	print ("stripping checksums.")
 	expected_ttx = strip_check_sum (expected_ttx)
 	actual_ttx = strip_check_sum (actual_ttx)
 
 	if not actual_ttx == expected_ttx:
-		for line in unified_diff(expected_ttx.splitlines(1), actual_ttx.splitlines(1)):
-			sys.stdout.write(line)
-		sys.stdout.flush()
+		for line in unified_diff (expected_ttx.splitlines (1), actual_ttx.splitlines (1)):
+			sys.stdout.write (line)
+		sys.stdout.flush ()
 		return fail_test(test, cli_args, 'ttx for expected and actual does not match.')
 
 	if should_check_ots:
 		print ("Checking output with ots-sanitize.")
-		if not check_ots(out_file):
-			return fail_test(test, cli_args, 'ots for subsetted file fails.')
+		if not check_ots (out_file):
+			return fail_test (test, cli_args, 'ots for subsetted file fails.')
 
 	return 0
 
-def run_ttx(file):
+def run_ttx (file):
 	print ("ttx %s" % file)
-	cli_args = ["ttx",
-		    "-q",
-		    "-o-",
-		    file]
-	return cmd(cli_args)
+	return cmd([ttx, "-q", "-o-", file])
 
 def strip_check_sum (ttx_string):
 	return re.sub ('checkSumAdjustment value=["]0x([0-9a-fA-F])+["]',
@@ -91,14 +110,13 @@ def strip_check_sum (ttx_string):
 		       ttx_string.decode (), count=1)
 
 def has_ots ():
-	_, returncode = cmd(["which", "ots-sanitize"])
-	if returncode:
+	if not ots_sanitize:
 		print("OTS is not present, skipping all ots checks.")
 		return False
 	return True
 
 def check_ots (path):
-	ots_report, returncode = cmd(["ots-sanitize", path])
+	ots_report, returncode = cmd ([ots_sanitize, path])
 	if returncode:
 		print("OTS Failure: %s" % ots_report);
 		return False
@@ -110,24 +128,19 @@ if not args or sys.argv[1].find('hb-subset') == -1 or not os.path.exists (sys.ar
 	sys.exit (1)
 hb_subset, args = args[0], args[1:]
 
-if not len(args):
+if not len (args):
 	print ("No tests supplied.")
 	sys.exit (1)
 
-_, returncode = cmd(["which", "ttx"])
-if returncode:
-	print("TTX is not present, skipping test.")
-	sys.exit (77)
-
 has_ots = has_ots()
 
 fails = 0
 for path in args:
-	with io.open(path, mode="r", encoding="utf-8") as f:
+	with io.open (path, mode="r", encoding="utf-8") as f:
 		print ("Running tests in " + path)
-		test_suite = SubsetTestSuite(path, f.read())
-		for test in test_suite.tests():
-			fails += run_test(test, has_ots)
+		test_suite = SubsetTestSuite (path, f.read())
+		for test in test_suite.tests ():
+			fails += run_test (test, has_ots)
 
 if fails != 0:
 	print (str (fails) + " test(s) failed.")
commit 159ddb872986f121818e816d2ea75d271075ba1f
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Sun Jun 24 23:09:16 2018 +0430

    Treat - just as /dev/stdin and remove one extra file reader (#1065)

diff --git a/util/options.cc b/util/options.cc
index 682e40c4..57cc4aa8 100644
--- a/util/options.cc
+++ b/util/options.cc
@@ -647,29 +647,20 @@ font_options_t::get_font (void) const
   if (!font_file)
     fail (true, "No font file set");
 
-  if (0 == strcmp (font_file, "-")) {
-    /* read it */
-    GString *gs = g_string_new (nullptr);
-    char buf[BUFSIZ];
+  const char *font_path = font_file;
+
+  if (0 == strcmp (font_path, "-"))
+  {
 #if defined(_WIN32) || defined(__CYGWIN__)
     setmode (fileno (stdin), O_BINARY);
+    font_path = "STDIN";
+#else
+    font_path = "/dev/stdin";
 #endif
-    while (!feof (stdin)) {
-      size_t ret = fread (buf, 1, sizeof (buf), stdin);
-      if (ferror (stdin))
-	fail (false, "Failed reading font from standard input: %s",
-	      strerror (errno));
-      g_string_append_len (gs, buf, ret);
-    }
-    unsigned int len = gs->len;
-    char *font_data = g_string_free (gs, false);
-    blob = hb_blob_create (font_data, len,
-			   HB_MEMORY_MODE_WRITABLE, font_data,
-			   (hb_destroy_func_t) g_free);
-  } else {
-    blob = hb_blob_create_from_file (font_file);
   }
 
+  blob = hb_blob_create_from_file (font_path);
+
   if (blob == hb_blob_get_empty ())
     fail (false, "No such file or directory");
 


More information about the HarfBuzz mailing list