mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-03 01:36:17 +01:00
giochannel: ensure line terminator remains nul-terminated if needed
If the user passes -1 length to g_io_channel_set_line_term() along with a nul-terminated string, then calls g_io_channel_get_line_term() and decides to treat the result as nul-terminated rather than checking the length parameter, then the application will have a problem, because it's not nul-terminated. That's weird, since the input string was. Let's ensure the result is consistent: if you pass a nul-terminated string, the result is nul-terminated. If not, it's not. Also add a warning to g_io_channel_get_line_term(), since it's very strange for a gchar * return value to be anything other than a nul-terminated UTF-8 string. This is an API design bug, but we cannot fix it.
This commit is contained in:
parent
a893d622c0
commit
7c6b11df2d
@ -877,26 +877,31 @@ g_io_channel_set_line_term (GIOChannel *channel,
|
||||
const gchar *line_term,
|
||||
gint length)
|
||||
{
|
||||
guint length_unsigned;
|
||||
|
||||
g_return_if_fail (channel != NULL);
|
||||
g_return_if_fail (line_term == NULL || length != 0); /* Disallow "" */
|
||||
|
||||
g_free (channel->line_term);
|
||||
|
||||
if (line_term == NULL)
|
||||
length_unsigned = 0;
|
||||
{
|
||||
channel->line_term = NULL;
|
||||
channel->line_term_len = 0;
|
||||
}
|
||||
else if (length >= 0)
|
||||
length_unsigned = (guint) length;
|
||||
{
|
||||
/* We store the value nul-terminated even if the input is not */
|
||||
channel->line_term = g_malloc0 (length + 1);
|
||||
memcpy (channel->line_term, line_term, length);
|
||||
channel->line_term_len = (guint) length;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: We’re constrained by line_term_len being a guint here */
|
||||
/* We’re constrained by line_term_len being a guint here */
|
||||
gsize length_size = strlen (line_term);
|
||||
g_return_if_fail (length_size <= G_MAXUINT);
|
||||
length_unsigned = (guint) length_size;
|
||||
channel->line_term = g_strdup (line_term);
|
||||
channel->line_term_len = (guint) length_size;
|
||||
}
|
||||
|
||||
g_free (channel->line_term);
|
||||
channel->line_term = line_term ? g_memdup2 (line_term, length_unsigned) : NULL;
|
||||
channel->line_term_len = length_unsigned;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -906,7 +911,8 @@ g_io_channel_set_line_term (GIOChannel *channel,
|
||||
*
|
||||
* This returns the string that #GIOChannel uses to determine
|
||||
* where in the file a line break occurs. A value of %NULL
|
||||
* indicates autodetection.
|
||||
* indicates autodetection. Since 2.84, the return value is always
|
||||
* nul-terminated.
|
||||
*
|
||||
* Returns: The line termination string. This value
|
||||
* is owned by GLib and must not be freed.
|
||||
|
@ -178,6 +178,8 @@ test_read_line_embedded_nuls (void)
|
||||
GError *local_error = NULL;
|
||||
gchar *line = NULL;
|
||||
gsize line_length, terminator_pos;
|
||||
const gchar *line_term;
|
||||
gint line_term_length;
|
||||
GIOStatus status;
|
||||
|
||||
g_test_summary ("Test that reading a line containing embedded nuls works "
|
||||
@ -200,6 +202,11 @@ test_read_line_embedded_nuls (void)
|
||||
* Use length -1 here to exercise glib#2323; the case where length > 0
|
||||
* is covered in glib/tests/protocol.c. */
|
||||
g_io_channel_set_line_term (channel, "\n", -1);
|
||||
|
||||
line_term = g_io_channel_get_line_term (channel, &line_term_length);
|
||||
g_assert_cmpstr (line_term, ==, "\n");
|
||||
g_assert_cmpint (line_term_length, ==, 1);
|
||||
|
||||
g_io_channel_set_encoding (channel, NULL, &local_error);
|
||||
g_assert_no_error (local_error);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user