[blob] Add failing versions of create API

Fixes https://github.com/harfbuzz/harfbuzz/issues/2567

New API:
+hb_blob_create_or_fail()
+hb_blob_create_from_file_or_fail()

Use these in util/ to distinguish empty file from not-found file.
Only err on the latter.
This commit is contained in:
Behdad Esfahbod 2021-06-14 15:46:04 -06:00
parent 2fc8d0e6f0
commit bdfed8f113
18 changed files with 132 additions and 54 deletions

View File

@ -21,7 +21,9 @@ hb_aat_layout_has_tracking
<SECTION> <SECTION>
<FILE>hb-blob</FILE> <FILE>hb-blob</FILE>
hb_blob_create hb_blob_create
hb_blob_create_or_fail
hb_blob_create_from_file hb_blob_create_from_file
hb_blob_create_from_file_or_fail
hb_blob_create_sub_blob hb_blob_create_sub_blob
hb_blob_copy_writable_or_fail hb_blob_copy_writable_or_fail
hb_blob_destroy hb_blob_destroy

View File

@ -241,7 +241,7 @@
</listitem> </listitem>
</orderedlist> </orderedlist>
<programlisting language="C"> <programlisting language="C">
hb_blob_t *blob = hb_blob_create_from_file(filename); hb_blob_t *blob = hb_blob_create_from_file(filename); /* or hb_blob_create_from_file_or_fail() */
hb_face_t *face = hb_face_create(blob, 0); hb_face_t *face = hb_face_create(blob, 0);
hb_font_t *font = hb_font_create(face); hb_font_t *font = hb_font_create(face);
</programlisting> </programlisting>

View File

@ -58,8 +58,8 @@ static void draw (benchmark::State &state, const char *font_path, bool is_var, b
hb_font_t *font; hb_font_t *font;
unsigned num_glyphs; unsigned num_glyphs;
{ {
hb_blob_t *blob = hb_blob_create_from_file (font_path); hb_blob_t *blob = hb_blob_create_from_file_or_fail (font_path);
assert (hb_blob_get_length (blob)); assert (blob);
hb_face_t *face = hb_face_create (blob, 0); hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob); hb_blob_destroy (blob);
num_glyphs = hb_face_get_glyph_count (face); num_glyphs = hb_face_get_glyph_count (face);

View File

@ -13,8 +13,8 @@ static void extents (benchmark::State &state, const char *font_path, bool is_var
hb_font_t *font; hb_font_t *font;
unsigned num_glyphs; unsigned num_glyphs;
{ {
hb_blob_t *blob = hb_blob_create_from_file (font_path); hb_blob_t *blob = hb_blob_create_from_file_or_fail (font_path);
assert (hb_blob_get_length (blob)); assert (blob);
hb_face_t *face = hb_face_create (blob, 0); hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob); hb_blob_destroy (blob);
num_glyphs = hb_face_get_glyph_count (face); num_glyphs = hb_face_get_glyph_count (face);

View File

@ -8,18 +8,18 @@ static void shape (benchmark::State &state, const char *text_path,
{ {
hb_font_t *font; hb_font_t *font;
{ {
hb_blob_t *blob = hb_blob_create_from_file (font_path); hb_blob_t *blob = hb_blob_create_from_file_or_fail (font_path);
assert (hb_blob_get_length (blob)); assert (blob);
hb_face_t *face = hb_face_create (blob, 0); hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob); hb_blob_destroy (blob);
font = hb_font_create (face); font = hb_font_create (face);
hb_face_destroy (face); hb_face_destroy (face);
} }
hb_blob_t *text_blob = hb_blob_create_from_file (text_path); hb_blob_t *text_blob = hb_blob_create_from_file_or_fail (text_path);
assert (text_blob);
unsigned text_length; unsigned text_length;
const char *text = hb_blob_get_data (text_blob, &text_length); const char *text = hb_blob_get_data (text_blob, &text_length);
assert (text_length);
hb_buffer_t *buf = hb_buffer_create (); hb_buffer_t *buf = hb_buffer_create ();
for (auto _ : state) for (auto _ : state)

View File

@ -71,15 +71,49 @@ hb_blob_create (const char *data,
hb_memory_mode_t mode, hb_memory_mode_t mode,
void *user_data, void *user_data,
hb_destroy_func_t destroy) hb_destroy_func_t destroy)
{
if (!length)
return hb_blob_get_empty ();
hb_blob_t *blob = hb_blob_create_or_fail (data, length, mode,
user_data, destroy);
return likely (blob) ? blob : hb_blob_get_empty ();
}
/**
* hb_blob_create_or_fail: (skip)
* @data: Pointer to blob data.
* @length: Length of @data in bytes.
* @mode: Memory mode for @data.
* @user_data: Data parameter to pass to @destroy.
* @destroy: (nullable): Callback to call when @data is not needed anymore.
*
* Creates a new "blob" object wrapping @data. The @mode parameter is used
* to negotiate ownership and lifecycle of @data.
*
* Note that this function returns a freshly-allocated empty blob even if @length
* is zero. This is in contrast to hb_blob_create(), which returns the singleton
* empty blob (as returned by hb_blob_get_empty()) if @length is zero.
*
* Return value: New blob, or %NULL if failed. Destroy with hb_blob_destroy().
*
* Since: REPLACEME
**/
hb_blob_t *
hb_blob_create_or_fail (const char *data,
unsigned int length,
hb_memory_mode_t mode,
void *user_data,
hb_destroy_func_t destroy)
{ {
hb_blob_t *blob; hb_blob_t *blob;
if (!length || if (length >= 1u << 31 ||
length >= 1u << 31 || !(blob = hb_object_create<hb_blob_t> ()))
!(blob = hb_object_create<hb_blob_t> ())) { {
if (destroy) if (destroy)
destroy (user_data); destroy (user_data);
return hb_blob_get_empty (); return nullptr;
} }
blob->data = data; blob->data = data;
@ -91,9 +125,10 @@ hb_blob_create (const char *data,
if (blob->mode == HB_MEMORY_MODE_DUPLICATE) { if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
blob->mode = HB_MEMORY_MODE_READONLY; blob->mode = HB_MEMORY_MODE_READONLY;
if (!blob->try_make_writable ()) { if (!blob->try_make_writable ())
{
hb_blob_destroy (blob); hb_blob_destroy (blob);
return hb_blob_get_empty (); return nullptr;
} }
} }
@ -561,12 +596,32 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file)
* Creates a new blob containing the data from the * Creates a new blob containing the data from the
* specified binary font file. * specified binary font file.
* *
* Returns: An #hb_blob_t pointer with the content of the file * Returns: An #hb_blob_t pointer with the content of the file,
* or hb_blob_get_empty() if failed.
* *
* Since: 1.7.7 * Since: 1.7.7
**/ **/
hb_blob_t * hb_blob_t *
hb_blob_create_from_file (const char *file_name) hb_blob_create_from_file (const char *file_name)
{
hb_blob_t *blob = hb_blob_create_from_file_or_fail (file_name);
return likely (blob) ? blob : hb_blob_get_empty ();
}
/**
* hb_blob_create_from_file_or_fail:
* @file_name: A font filename
*
* Creates a new blob containing the data from the
* specified binary font file.
*
* Returns: An #hb_blob_t pointer with the content of the file,
* or %NULL if failed.
*
* Since: REPLACEME
**/
hb_blob_t *
hb_blob_create_from_file_or_fail (const char *file_name)
{ {
/* Adopted from glib's gmappedfile.c with Matthias Clasen and /* Adopted from glib's gmappedfile.c with Matthias Clasen and
Allison Lortie permission but changed a lot to suit our need. */ Allison Lortie permission but changed a lot to suit our need. */
@ -601,7 +656,7 @@ hb_blob_create_from_file (const char *file_name)
close (fd); close (fd);
return hb_blob_create (file->contents, file->length, return hb_blob_create_or_fail (file->contents, file->length,
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
(hb_destroy_func_t) _hb_mapped_file_destroy); (hb_destroy_func_t) _hb_mapped_file_destroy);
@ -661,7 +716,7 @@ fail_without_close:
if (unlikely (!file->contents)) goto fail; if (unlikely (!file->contents)) goto fail;
CloseHandle (fd); CloseHandle (fd);
return hb_blob_create (file->contents, file->length, return hb_blob_create_or_fail (file->contents, file->length,
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
(hb_destroy_func_t) _hb_mapped_file_destroy); (hb_destroy_func_t) _hb_mapped_file_destroy);
@ -676,7 +731,7 @@ fail_without_close:
It's used as a fallback for systems without mmap or to read from pipes */ It's used as a fallback for systems without mmap or to read from pipes */
unsigned long len = 0, allocated = BUFSIZ * 16; unsigned long len = 0, allocated = BUFSIZ * 16;
char *data = (char *) malloc (allocated); char *data = (char *) malloc (allocated);
if (unlikely (!data)) return hb_blob_get_empty (); if (unlikely (!data)) return nullptr;
FILE *fp = fopen (file_name, "rb"); FILE *fp = fopen (file_name, "rb");
if (unlikely (!fp)) goto fread_fail_without_close; if (unlikely (!fp)) goto fread_fail_without_close;
@ -706,13 +761,13 @@ fail_without_close:
} }
fclose (fp); fclose (fp);
return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data, return hb_blob_create_or_fail (data, len, HB_MEMORY_MODE_WRITABLE, data,
(hb_destroy_func_t) free); (hb_destroy_func_t) free);
fread_fail: fread_fail:
fclose (fp); fclose (fp);
fread_fail_without_close: fread_fail_without_close:
free (data); free (data);
return hb_blob_get_empty (); return nullptr;
} }
#endif /* !HB_NO_OPEN */ #endif /* !HB_NO_OPEN */

View File

@ -90,9 +90,19 @@ hb_blob_create (const char *data,
void *user_data, void *user_data,
hb_destroy_func_t destroy); hb_destroy_func_t destroy);
HB_EXTERN hb_blob_t *
hb_blob_create_or_fail (const char *data,
unsigned int length,
hb_memory_mode_t mode,
void *user_data,
hb_destroy_func_t destroy);
HB_EXTERN hb_blob_t * HB_EXTERN hb_blob_t *
hb_blob_create_from_file (const char *file_name); hb_blob_create_from_file (const char *file_name);
HB_EXTERN hb_blob_t *
hb_blob_create_from_file_or_fail (const char *file_name);
/* Always creates with MEMORY_MODE_READONLY. /* Always creates with MEMORY_MODE_READONLY.
* Even if the parent blob is writable, we don't * Even if the parent blob is writable, we don't
* want the user of the sub-blob to be able to * want the user of the sub-blob to be able to

View File

@ -33,12 +33,13 @@
#include "hb.h" #include "hb.h"
#include "hb-ot.h" #include "hb-ot.h"
#include <stdlib.h> #include <cassert>
#include <stdio.h> #include <cstdlib>
#include <string.h> #include <cstdio>
#include <cstring>
#ifdef HB_NO_OPEN #ifdef HB_NO_OPEN
#define hb_blob_create_from_file(x) hb_blob_get_empty () #define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif #endif
#if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW) && defined(HB_EXPERIMENTAL_API) #if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW) && defined(HB_EXPERIMENTAL_API)
@ -505,7 +506,8 @@ main (int argc, char **argv)
exit (1); exit (1);
} }
hb_blob_t *blob = hb_blob_create_from_file (argv[1]); hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
assert (blob);
printf ("Opened font file %s: %d bytes long\n", argv[1], hb_blob_get_length (blob)); printf ("Opened font file %s: %d bytes long\n", argv[1], hb_blob_get_length (blob));
#ifndef MAIN_CC_NO_PRIVATE_API #ifndef MAIN_CC_NO_PRIVATE_API
print_layout_info_using_private_api (blob); print_layout_info_using_private_api (blob);

View File

@ -33,7 +33,7 @@
#endif #endif
#ifdef HB_NO_OPEN #ifdef HB_NO_OPEN
#define hb_blob_create_from_file(x) hb_blob_get_empty () #define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif #endif
int int
@ -48,7 +48,8 @@ main (int argc, char **argv)
exit (1); exit (1);
} }
hb_blob_t *blob = hb_blob_create_from_file (argv[1]); hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0 /* first face */); hb_face_t *face = hb_face_create (blob, 0 /* first face */);
hb_blob_destroy (blob); hb_blob_destroy (blob);
blob = nullptr; blob = nullptr;

View File

@ -30,7 +30,7 @@
#include "hb-ot.h" #include "hb-ot.h"
#ifdef HB_NO_OPEN #ifdef HB_NO_OPEN
#define hb_blob_create_from_file(x) hb_blob_get_empty () #define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif #endif
int int
@ -42,7 +42,8 @@ main (int argc, char **argv)
} }
/* Create the face */ /* Create the face */
hb_blob_t *blob = hb_blob_create_from_file (argv[1]); hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0 /* first face */); hb_face_t *face = hb_face_create (blob, 0 /* first face */);
hb_blob_destroy (blob); hb_blob_destroy (blob);
blob = nullptr; blob = nullptr;

View File

@ -34,7 +34,7 @@
#endif #endif
#ifdef HB_NO_OPEN #ifdef HB_NO_OPEN
#define hb_blob_create_from_file(x) hb_blob_get_empty () #define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif #endif
int int
@ -46,7 +46,8 @@ main (int argc, char **argv)
} }
/* Create the face */ /* Create the face */
hb_blob_t *blob = hb_blob_create_from_file (argv[1]); hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0 /* first face */); hb_face_t *face = hb_face_create (blob, 0 /* first face */);
hb_blob_destroy (blob); hb_blob_destroy (blob);
blob = nullptr; blob = nullptr;

View File

@ -28,7 +28,7 @@
#include "hb-ot.h" #include "hb-ot.h"
#ifdef HB_NO_OPEN #ifdef HB_NO_OPEN
#define hb_blob_create_from_file(x) hb_blob_get_empty () #define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif #endif
int int
@ -39,7 +39,8 @@ main (int argc, char **argv)
exit (1); exit (1);
} }
hb_blob_t *blob = hb_blob_create_from_file (argv[1]); hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0 /* first face */); hb_face_t *face = hb_face_create (blob, 0 /* first face */);
hb_font_t *font = hb_font_create (face); hb_font_t *font = hb_font_create (face);
hb_blob_destroy (blob); hb_blob_destroy (blob);

View File

@ -26,7 +26,7 @@
#include "hb-ot.h" #include "hb-ot.h"
#ifdef HB_NO_OPEN #ifdef HB_NO_OPEN
#define hb_blob_create_from_file(x) hb_blob_get_empty () #define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif #endif
int int
@ -37,7 +37,8 @@ main (int argc, char **argv)
exit (1); exit (1);
} }
hb_blob_t *blob = hb_blob_create_from_file (argv[1]); hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0 /* first face */); hb_face_t *face = hb_face_create (blob, 0 /* first face */);
hb_blob_destroy (blob); hb_blob_destroy (blob);
blob = nullptr; blob = nullptr;

View File

@ -28,7 +28,7 @@
#include "hb-ot.h" #include "hb-ot.h"
#ifdef HB_NO_OPEN #ifdef HB_NO_OPEN
#define hb_blob_create_from_file(x) hb_blob_get_empty () #define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif #endif
int int
@ -39,7 +39,8 @@ main (int argc, char **argv)
exit (1); exit (1);
} }
hb_blob_t *blob = hb_blob_create_from_file (argv[1]); hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0 /* first face */); hb_face_t *face = hb_face_create (blob, 0 /* first face */);
hb_blob_destroy (blob); hb_blob_destroy (blob);
blob = nullptr; blob = nullptr;

View File

@ -31,7 +31,7 @@
#endif #endif
#ifdef HB_NO_OPEN #ifdef HB_NO_OPEN
#define hb_blob_create_from_file(x) hb_blob_get_empty () #define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif #endif
int int
@ -42,7 +42,8 @@ main (int argc, char **argv)
exit (1); exit (1);
} }
hb_blob_t *blob = hb_blob_create_from_file (argv[1]); hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
assert (blob);
printf ("Opened font file %s: %u bytes long\n", argv[1], hb_blob_get_length (blob)); printf ("Opened font file %s: %u bytes long\n", argv[1], hb_blob_get_length (blob));
/* Create the face */ /* Create the face */

View File

@ -296,9 +296,9 @@ hb_test_open_font_file (const char *font_path)
char *path = g_strdup (font_path); char *path = g_strdup (font_path);
#endif #endif
hb_blob_t *blob = hb_blob_create_from_file (path); hb_blob_t *blob = hb_blob_create_from_file_or_fail (path);
hb_face_t *face; hb_face_t *face;
if (hb_blob_get_length (blob) == 0) if (!blob)
g_error ("Font %s not found.", path); g_error ("Font %s not found.", path);
face = hb_face_create (blob, 0); face = hb_face_create (blob, 0);

View File

@ -1,16 +1,18 @@
#include "hb-fuzzer.hh" #include "hb-fuzzer.hh"
#include <stdio.h> #include <cassert>
#include <cstdio>
int main (int argc, char **argv) int main (int argc, char **argv)
{ {
for (int i = 1; i < argc; i++) for (int i = 1; i < argc; i++)
{ {
hb_blob_t *blob = hb_blob_create_from_file (argv[i]); hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[i]);
assert (blob);
unsigned int len; unsigned len = 0;
const char *font_data = hb_blob_get_data (blob, &len); const char *font_data = hb_blob_get_data (blob, &len);
printf ("%s%s\n", argv[i], len ? "" : " (note: not found or was empty)"); printf ("%s (%u bytes)\n", argv[i], len);
LLVMFuzzerTestOneInput ((const uint8_t *) font_data, len); LLVMFuzzerTestOneInput ((const uint8_t *) font_data, len);

View File

@ -696,10 +696,10 @@ font_options_t::get_font () const
#endif #endif
} }
blob = hb_blob_create_from_file (font_path); blob = hb_blob_create_from_file_or_fail (font_path);
if (blob == hb_blob_get_empty ()) if (!blob)
fail (false, "Couldn't read or find %s, or it was empty.", font_path); fail (false, "%s: Failed reading file", font_path);
/* Create the face */ /* Create the face */
hb_face_t *face = hb_face_create (blob, face_index); hb_face_t *face = hb_face_create (blob, face_index);