mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-09 19:06:15 +01:00
gfile: Rewrite load_contents() to use realloc()
GByteArray is limited to 4GB in size and the current code silently overflows when that happens. Replace both load_contents() and load_contents_async() implementations with a version that uses realloc() and gsize to maintain the array.
This commit is contained in:
parent
a57f0b190a
commit
e8254f14fd
73
gio/gfile.c
73
gio/gfile.c
@ -8086,7 +8086,8 @@ g_file_load_contents (GFile *file,
|
|||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
GFileInputStream *in;
|
GFileInputStream *in;
|
||||||
GByteArray *content;
|
char *data;
|
||||||
|
gsize size;
|
||||||
gsize pos;
|
gsize pos;
|
||||||
gssize res;
|
gssize res;
|
||||||
GFileInfo *info;
|
GFileInfo *info;
|
||||||
@ -8098,17 +8099,22 @@ g_file_load_contents (GFile *file,
|
|||||||
if (in == NULL)
|
if (in == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
content = g_byte_array_new ();
|
size = GET_CONTENT_BLOCK_SIZE;
|
||||||
|
data = g_malloc (GET_CONTENT_BLOCK_SIZE);
|
||||||
pos = 0;
|
pos = 0;
|
||||||
|
|
||||||
g_byte_array_set_size (content, pos + GET_CONTENT_BLOCK_SIZE + 1);
|
|
||||||
while ((res = g_input_stream_read (G_INPUT_STREAM (in),
|
while ((res = g_input_stream_read (G_INPUT_STREAM (in),
|
||||||
content->data + pos,
|
data + pos,
|
||||||
GET_CONTENT_BLOCK_SIZE,
|
GET_CONTENT_BLOCK_SIZE,
|
||||||
cancellable, error)) > 0)
|
cancellable, error)) > 0)
|
||||||
{
|
{
|
||||||
pos += res;
|
pos += res;
|
||||||
g_byte_array_set_size (content, pos + GET_CONTENT_BLOCK_SIZE + 1);
|
if (size - pos < GET_CONTENT_BLOCK_SIZE)
|
||||||
|
{
|
||||||
|
g_assert (size <= G_MAXSIZE / 2);
|
||||||
|
size *= 2;
|
||||||
|
data = g_realloc (data, size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (etag_out)
|
if (etag_out)
|
||||||
@ -8133,17 +8139,19 @@ g_file_load_contents (GFile *file,
|
|||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
/* error is set already */
|
/* error is set already */
|
||||||
g_byte_array_free (content, TRUE);
|
g_free (data);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length)
|
if (length)
|
||||||
*length = pos;
|
*length = pos;
|
||||||
|
|
||||||
/* Zero terminate (we got an extra byte allocated for this */
|
/* Zero terminate (allocating extra bytes if needed) */
|
||||||
content->data[pos] = 0;
|
if (pos >= size)
|
||||||
|
data = g_realloc (data, pos + 1);
|
||||||
|
data[pos] = 0;
|
||||||
|
|
||||||
*contents = (char *)g_byte_array_free (content, FALSE);
|
*contents = g_steal_pointer (&data);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -8151,7 +8159,8 @@ g_file_load_contents (GFile *file,
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
GTask *task;
|
GTask *task;
|
||||||
GFileReadMoreCallback read_more_callback;
|
GFileReadMoreCallback read_more_callback;
|
||||||
GByteArray *content;
|
char *data;
|
||||||
|
gsize size;
|
||||||
gsize pos;
|
gsize pos;
|
||||||
char *etag;
|
char *etag;
|
||||||
} LoadContentsData;
|
} LoadContentsData;
|
||||||
@ -8160,12 +8169,31 @@ typedef struct {
|
|||||||
static void
|
static void
|
||||||
load_contents_data_free (LoadContentsData *data)
|
load_contents_data_free (LoadContentsData *data)
|
||||||
{
|
{
|
||||||
if (data->content)
|
g_clear_pointer (&data->data, g_free);
|
||||||
g_byte_array_free (data->content, TRUE);
|
|
||||||
g_free (data->etag);
|
g_free (data->etag);
|
||||||
g_free (data);
|
g_free (data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_contents_data_ensure_space (LoadContentsData *data,
|
||||||
|
gsize space)
|
||||||
|
{
|
||||||
|
if (data->size - data->pos < space)
|
||||||
|
{
|
||||||
|
if (data->data == NULL)
|
||||||
|
{
|
||||||
|
data->size = space;
|
||||||
|
data->data = g_malloc (space);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_assert (data->size <= G_MAXSIZE / 2);
|
||||||
|
data->size *= 2;
|
||||||
|
data->data = g_realloc (data->data, data->size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
load_contents_close_callback (GObject *obj,
|
load_contents_close_callback (GObject *obj,
|
||||||
GAsyncResult *close_res,
|
GAsyncResult *close_res,
|
||||||
@ -8238,12 +8266,10 @@ load_contents_read_callback (GObject *obj,
|
|||||||
{
|
{
|
||||||
data->pos += read_size;
|
data->pos += read_size;
|
||||||
|
|
||||||
g_byte_array_set_size (data->content,
|
load_contents_data_ensure_space (data, GET_CONTENT_BLOCK_SIZE);
|
||||||
data->pos + GET_CONTENT_BLOCK_SIZE);
|
|
||||||
|
|
||||||
|
|
||||||
if (data->read_more_callback &&
|
if (data->read_more_callback &&
|
||||||
!data->read_more_callback ((char *)data->content->data, data->pos,
|
!data->read_more_callback (data->data, data->pos,
|
||||||
g_async_result_get_user_data (G_ASYNC_RESULT (data->task))))
|
g_async_result_get_user_data (G_ASYNC_RESULT (data->task))))
|
||||||
g_file_input_stream_query_info_async (G_FILE_INPUT_STREAM (stream),
|
g_file_input_stream_query_info_async (G_FILE_INPUT_STREAM (stream),
|
||||||
G_FILE_ATTRIBUTE_ETAG_VALUE,
|
G_FILE_ATTRIBUTE_ETAG_VALUE,
|
||||||
@ -8253,7 +8279,7 @@ load_contents_read_callback (GObject *obj,
|
|||||||
data);
|
data);
|
||||||
else
|
else
|
||||||
g_input_stream_read_async (stream,
|
g_input_stream_read_async (stream,
|
||||||
data->content->data + data->pos,
|
data->data + data->pos,
|
||||||
GET_CONTENT_BLOCK_SIZE,
|
GET_CONTENT_BLOCK_SIZE,
|
||||||
0,
|
0,
|
||||||
g_task_get_cancellable (data->task),
|
g_task_get_cancellable (data->task),
|
||||||
@ -8276,10 +8302,9 @@ load_contents_open_callback (GObject *obj,
|
|||||||
|
|
||||||
if (stream)
|
if (stream)
|
||||||
{
|
{
|
||||||
g_byte_array_set_size (data->content,
|
load_contents_data_ensure_space (data, GET_CONTENT_BLOCK_SIZE);
|
||||||
data->pos + GET_CONTENT_BLOCK_SIZE);
|
|
||||||
g_input_stream_read_async (G_INPUT_STREAM (stream),
|
g_input_stream_read_async (G_INPUT_STREAM (stream),
|
||||||
data->content->data + data->pos,
|
data->data + data->pos,
|
||||||
GET_CONTENT_BLOCK_SIZE,
|
GET_CONTENT_BLOCK_SIZE,
|
||||||
0,
|
0,
|
||||||
g_task_get_cancellable (data->task),
|
g_task_get_cancellable (data->task),
|
||||||
@ -8329,7 +8354,6 @@ g_file_load_partial_contents_async (GFile *file,
|
|||||||
|
|
||||||
data = g_new0 (LoadContentsData, 1);
|
data = g_new0 (LoadContentsData, 1);
|
||||||
data->read_more_callback = read_more_callback;
|
data->read_more_callback = read_more_callback;
|
||||||
data->content = g_byte_array_new ();
|
|
||||||
|
|
||||||
data->task = g_task_new (file, cancellable, callback, user_data);
|
data->task = g_task_new (file, cancellable, callback, user_data);
|
||||||
g_task_set_source_tag (data->task, g_file_load_partial_contents_async);
|
g_task_set_source_tag (data->task, g_file_load_partial_contents_async);
|
||||||
@ -8398,11 +8422,10 @@ g_file_load_partial_contents_finish (GFile *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Zero terminate */
|
/* Zero terminate */
|
||||||
g_byte_array_set_size (data->content, data->pos + 1);
|
load_contents_data_ensure_space (data, 1);
|
||||||
data->content->data[data->pos] = 0;
|
data->data[data->pos] = 0;
|
||||||
|
|
||||||
*contents = (char *)g_byte_array_free (data->content, FALSE);
|
*contents = g_steal_pointer (&data->data);
|
||||||
data->content = NULL;
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user