[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>
<FILE>hb-blob</FILE>
hb_blob_create
hb_blob_create_or_fail
hb_blob_create_from_file
hb_blob_create_from_file_or_fail
hb_blob_create_sub_blob
hb_blob_copy_writable_or_fail
hb_blob_destroy

View File

@ -241,7 +241,7 @@
</listitem>
</orderedlist>
<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_font_t *font = hb_font_create(face);
</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;
unsigned num_glyphs;
{
hb_blob_t *blob = hb_blob_create_from_file (font_path);
assert (hb_blob_get_length (blob));
hb_blob_t *blob = hb_blob_create_from_file_or_fail (font_path);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
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;
unsigned num_glyphs;
{
hb_blob_t *blob = hb_blob_create_from_file (font_path);
assert (hb_blob_get_length (blob));
hb_blob_t *blob = hb_blob_create_from_file_or_fail (font_path);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
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_blob_t *blob = hb_blob_create_from_file (font_path);
assert (hb_blob_get_length (blob));
hb_blob_t *blob = hb_blob_create_from_file_or_fail (font_path);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
font = hb_font_create (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;
const char *text = hb_blob_get_data (text_blob, &text_length);
assert (text_length);
hb_buffer_t *buf = hb_buffer_create ();
for (auto _ : state)

View File

@ -71,15 +71,49 @@ hb_blob_create (const char *data,
hb_memory_mode_t mode,
void *user_data,
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;
if (!length ||
length >= 1u << 31 ||
!(blob = hb_object_create<hb_blob_t> ())) {
if (length >= 1u << 31 ||
!(blob = hb_object_create<hb_blob_t> ()))
{
if (destroy)
destroy (user_data);
return hb_blob_get_empty ();
return nullptr;
}
blob->data = data;
@ -91,9 +125,10 @@ hb_blob_create (const char *data,
if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
blob->mode = HB_MEMORY_MODE_READONLY;
if (!blob->try_make_writable ()) {
if (!blob->try_make_writable ())
{
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
* 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
**/
hb_blob_t *
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
Allison Lortie permission but changed a lot to suit our need. */
@ -601,9 +656,9 @@ hb_blob_create_from_file (const char *file_name)
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);
return hb_blob_create_or_fail (file->contents, file->length,
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
(hb_destroy_func_t) _hb_mapped_file_destroy);
fail:
close (fd);
@ -661,9 +716,9 @@ fail_without_close:
if (unlikely (!file->contents)) goto fail;
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);
return hb_blob_create_or_fail (file->contents, file->length,
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
(hb_destroy_func_t) _hb_mapped_file_destroy);
fail:
CloseHandle (fd);
@ -676,7 +731,7 @@ fail_without_close:
It's used as a fallback for systems without mmap or to read from pipes */
unsigned long len = 0, allocated = BUFSIZ * 16;
char *data = (char *) malloc (allocated);
if (unlikely (!data)) return hb_blob_get_empty ();
if (unlikely (!data)) return nullptr;
FILE *fp = fopen (file_name, "rb");
if (unlikely (!fp)) goto fread_fail_without_close;
@ -706,13 +761,13 @@ fail_without_close:
}
fclose (fp);
return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data,
(hb_destroy_func_t) free);
return hb_blob_create_or_fail (data, len, HB_MEMORY_MODE_WRITABLE, data,
(hb_destroy_func_t) free);
fread_fail:
fclose (fp);
fread_fail_without_close:
free (data);
return hb_blob_get_empty ();
return nullptr;
}
#endif /* !HB_NO_OPEN */

View File

@ -90,9 +90,19 @@ hb_blob_create (const char *data,
void *user_data,
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_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.
* Even if the parent blob is writable, we don't
* want the user of the sub-blob to be able to

View File

@ -33,12 +33,13 @@
#include "hb.h"
#include "hb-ot.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cassert>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#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
#if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW) && defined(HB_EXPERIMENTAL_API)
@ -505,7 +506,8 @@ main (int argc, char **argv)
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));
#ifndef MAIN_CC_NO_PRIVATE_API
print_layout_info_using_private_api (blob);

View File

@ -33,7 +33,7 @@
#endif
#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
int
@ -48,7 +48,8 @@ main (int argc, char **argv)
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_blob_destroy (blob);
blob = nullptr;

View File

@ -30,7 +30,7 @@
#include "hb-ot.h"
#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
int
@ -42,7 +42,8 @@ main (int argc, char **argv)
}
/* 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_blob_destroy (blob);
blob = nullptr;

View File

@ -34,7 +34,7 @@
#endif
#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
int
@ -46,7 +46,8 @@ main (int argc, char **argv)
}
/* 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_blob_destroy (blob);
blob = nullptr;

View File

@ -28,7 +28,7 @@
#include "hb-ot.h"
#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
int
@ -39,7 +39,8 @@ main (int argc, char **argv)
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_font_t *font = hb_font_create (face);
hb_blob_destroy (blob);

View File

@ -26,7 +26,7 @@
#include "hb-ot.h"
#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
int
@ -37,7 +37,8 @@ main (int argc, char **argv)
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_blob_destroy (blob);
blob = nullptr;

View File

@ -28,7 +28,7 @@
#include "hb-ot.h"
#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
int
@ -39,7 +39,8 @@ main (int argc, char **argv)
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_blob_destroy (blob);
blob = nullptr;

View File

@ -31,7 +31,7 @@
#endif
#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
int
@ -42,7 +42,8 @@ main (int argc, char **argv)
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));
/* Create the face */

View File

@ -296,9 +296,9 @@ hb_test_open_font_file (const char *font_path)
char *path = g_strdup (font_path);
#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;
if (hb_blob_get_length (blob) == 0)
if (!blob)
g_error ("Font %s not found.", path);
face = hb_face_create (blob, 0);

View File

@ -1,16 +1,18 @@
#include "hb-fuzzer.hh"
#include <stdio.h>
#include <cassert>
#include <cstdio>
int main (int argc, char **argv)
{
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);
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);

View File

@ -696,10 +696,10 @@ font_options_t::get_font () const
#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 ())
fail (false, "Couldn't read or find %s, or it was empty.", font_path);
if (!blob)
fail (false, "%s: Failed reading file", font_path);
/* Create the face */
hb_face_t *face = hb_face_create (blob, face_index);