mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-28 20:51:13 +00:00
0bb6d590cc
Upstream seems to have stopped doing releases, but we need to update for better Windows and Visual Studio support. This patch only updates the libcheck sources and ignores the compatibility sources for now. https://bugzilla.gnome.org/show_bug.cgi?id=775870
493 lines
10 KiB
C
493 lines
10 KiB
C
/*
|
|
* Check: a unit test framework for C
|
|
* Copyright (C) 2001, 2002 Arien Malec
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
|
* MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "libcompat/libcompat.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include "internal-check.h"
|
|
#include "check_error.h"
|
|
#include "check_list.h"
|
|
#include "check_impl.h"
|
|
#include "check_pack.h"
|
|
|
|
#ifndef HAVE_PTHREAD
|
|
#define pthread_mutex_lock(arg)
|
|
#define pthread_mutex_unlock(arg)
|
|
#define pthread_cleanup_push(f,a) {
|
|
#define pthread_cleanup_pop(e) }
|
|
#endif
|
|
|
|
/* Maximum size for one message in the message stream. */
|
|
#define CK_MAX_MSG_SIZE 8192
|
|
/* This is used to implement a sliding window on the receiving
|
|
* side. When sending messages, we assure that no single message
|
|
* is bigger than this (actually we check against CK_MAX_MSG_SIZE/2).
|
|
* The usual size for a message is less than 80 bytes.
|
|
* All this is done instead of the previous approach to allocate (actually
|
|
* continuously reallocate) one big chunk for the whole message stream.
|
|
* Problems were seen in the wild with up to 4 GB reallocations.
|
|
*/
|
|
|
|
|
|
/* typedef an unsigned int that has at least 4 bytes */
|
|
typedef uint32_t ck_uint32;
|
|
|
|
|
|
static void pack_int (char **buf, int val);
|
|
static int upack_int (char **buf);
|
|
static void pack_str (char **buf, const char *str);
|
|
static char *upack_str (char **buf);
|
|
|
|
static int pack_ctx (char **buf, CtxMsg * cmsg);
|
|
static int pack_loc (char **buf, LocMsg * lmsg);
|
|
static int pack_fail (char **buf, FailMsg * fmsg);
|
|
static int pack_duration (char **buf, DurationMsg * fmsg);
|
|
static void upack_ctx (char **buf, CtxMsg * cmsg);
|
|
static void upack_loc (char **buf, LocMsg * lmsg);
|
|
static void upack_fail (char **buf, FailMsg * fmsg);
|
|
static void upack_duration (char **buf, DurationMsg * fmsg);
|
|
|
|
static void check_type (int type, const char *file, int line);
|
|
static enum ck_msg_type upack_type (char **buf);
|
|
static void pack_type (char **buf, enum ck_msg_type type);
|
|
|
|
static int read_buf (FILE * fdes, int size, char *buf);
|
|
static int get_result (char *buf, RcvMsg * rmsg);
|
|
static void rcvmsg_update_ctx (RcvMsg * rmsg, enum ck_result_ctx ctx);
|
|
static void rcvmsg_update_loc (RcvMsg * rmsg, const char *file, int line);
|
|
static RcvMsg *rcvmsg_create (void);
|
|
void rcvmsg_free (RcvMsg * rmsg);
|
|
|
|
typedef int (*pfun) (char **, CheckMsg *);
|
|
typedef void (*upfun) (char **, CheckMsg *);
|
|
|
|
static pfun pftab[] = {
|
|
(pfun) pack_ctx,
|
|
(pfun) pack_fail,
|
|
(pfun) pack_loc,
|
|
(pfun) pack_duration
|
|
};
|
|
|
|
static upfun upftab[] = {
|
|
(upfun) upack_ctx,
|
|
(upfun) upack_fail,
|
|
(upfun) upack_loc,
|
|
(upfun) upack_duration
|
|
};
|
|
|
|
int
|
|
pack (enum ck_msg_type type, char **buf, CheckMsg * msg)
|
|
{
|
|
if (buf == NULL)
|
|
return -1;
|
|
if (msg == NULL)
|
|
return 0;
|
|
|
|
check_type (type, __FILE__, __LINE__);
|
|
|
|
return pftab[type] (buf, msg);
|
|
}
|
|
|
|
int
|
|
upack (char *buf, CheckMsg * msg, enum ck_msg_type *type)
|
|
{
|
|
char *obuf;
|
|
|
|
if (buf == NULL)
|
|
return -1;
|
|
|
|
obuf = buf;
|
|
|
|
*type = upack_type (&buf);
|
|
|
|
check_type (*type, __FILE__, __LINE__);
|
|
|
|
upftab[*type] (&buf, msg);
|
|
|
|
return buf - obuf;
|
|
}
|
|
|
|
static void
|
|
pack_int (char **buf, int val)
|
|
{
|
|
unsigned char *ubuf = (unsigned char *) *buf;
|
|
ck_uint32 uval = val;
|
|
|
|
ubuf[0] = (unsigned char) ((uval >> 24) & 0xFF);
|
|
ubuf[1] = (unsigned char) ((uval >> 16) & 0xFF);
|
|
ubuf[2] = (unsigned char) ((uval >> 8) & 0xFF);
|
|
ubuf[3] = (unsigned char) (uval & 0xFF);
|
|
|
|
*buf += 4;
|
|
}
|
|
|
|
static int
|
|
upack_int (char **buf)
|
|
{
|
|
unsigned char *ubuf = (unsigned char *) *buf;
|
|
ck_uint32 uval;
|
|
|
|
uval =
|
|
(ck_uint32) ((ubuf[0] << 24) | (ubuf[1] << 16) | (ubuf[2] << 8) |
|
|
ubuf[3]);
|
|
|
|
*buf += 4;
|
|
|
|
return (int) uval;
|
|
}
|
|
|
|
static void
|
|
pack_str (char **buf, const char *val)
|
|
{
|
|
int strsz;
|
|
|
|
if (val == NULL)
|
|
strsz = 0;
|
|
else
|
|
strsz = strlen (val);
|
|
|
|
pack_int (buf, strsz);
|
|
|
|
if (strsz > 0) {
|
|
memcpy (*buf, val, strsz);
|
|
*buf += strsz;
|
|
}
|
|
}
|
|
|
|
static char *
|
|
upack_str (char **buf)
|
|
{
|
|
char *val;
|
|
int strsz;
|
|
|
|
strsz = upack_int (buf);
|
|
|
|
if (strsz > 0) {
|
|
val = (char *) emalloc (strsz + 1);
|
|
memcpy (val, *buf, strsz);
|
|
val[strsz] = 0;
|
|
*buf += strsz;
|
|
} else {
|
|
val = (char *) emalloc (1);
|
|
*val = 0;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
static void
|
|
pack_type (char **buf, enum ck_msg_type type)
|
|
{
|
|
pack_int (buf, (int) type);
|
|
}
|
|
|
|
static enum ck_msg_type
|
|
upack_type (char **buf)
|
|
{
|
|
return (enum ck_msg_type) upack_int (buf);
|
|
}
|
|
|
|
|
|
static int
|
|
pack_ctx (char **buf, CtxMsg * cmsg)
|
|
{
|
|
char *ptr;
|
|
int len;
|
|
|
|
len = 4 + 4;
|
|
*buf = ptr = (char *) emalloc (len);
|
|
|
|
pack_type (&ptr, CK_MSG_CTX);
|
|
pack_int (&ptr, (int) cmsg->ctx);
|
|
|
|
return len;
|
|
}
|
|
|
|
static void
|
|
upack_ctx (char **buf, CtxMsg * cmsg)
|
|
{
|
|
cmsg->ctx = (enum ck_result_ctx) upack_int (buf);
|
|
}
|
|
|
|
static int
|
|
pack_duration (char **buf, DurationMsg * cmsg)
|
|
{
|
|
char *ptr;
|
|
int len;
|
|
|
|
len = 4 + 4;
|
|
*buf = ptr = (char *) emalloc (len);
|
|
|
|
pack_type (&ptr, CK_MSG_DURATION);
|
|
pack_int (&ptr, cmsg->duration);
|
|
|
|
return len;
|
|
}
|
|
|
|
static void
|
|
upack_duration (char **buf, DurationMsg * cmsg)
|
|
{
|
|
cmsg->duration = upack_int (buf);
|
|
}
|
|
|
|
static int
|
|
pack_loc (char **buf, LocMsg * lmsg)
|
|
{
|
|
char *ptr;
|
|
int len;
|
|
|
|
len = 4 + 4 + (lmsg->file ? strlen (lmsg->file) : 0) + 4;
|
|
*buf = ptr = (char *) emalloc (len);
|
|
|
|
pack_type (&ptr, CK_MSG_LOC);
|
|
pack_str (&ptr, lmsg->file);
|
|
pack_int (&ptr, lmsg->line);
|
|
|
|
return len;
|
|
}
|
|
|
|
static void
|
|
upack_loc (char **buf, LocMsg * lmsg)
|
|
{
|
|
lmsg->file = upack_str (buf);
|
|
lmsg->line = upack_int (buf);
|
|
}
|
|
|
|
static int
|
|
pack_fail (char **buf, FailMsg * fmsg)
|
|
{
|
|
char *ptr;
|
|
int len;
|
|
|
|
len = 4 + 4 + (fmsg->msg ? strlen (fmsg->msg) : 0);
|
|
*buf = ptr = (char *) emalloc (len);
|
|
|
|
pack_type (&ptr, CK_MSG_FAIL);
|
|
pack_str (&ptr, fmsg->msg);
|
|
|
|
return len;
|
|
}
|
|
|
|
static void
|
|
upack_fail (char **buf, FailMsg * fmsg)
|
|
{
|
|
fmsg->msg = upack_str (buf);
|
|
}
|
|
|
|
static void
|
|
check_type (int type, const char *file, int line)
|
|
{
|
|
if (type < 0 || type >= CK_MSG_LAST)
|
|
eprintf ("Bad message type arg %d", file, line, type);
|
|
}
|
|
|
|
#ifdef HAVE_PTHREAD
|
|
static pthread_mutex_t ck_mutex_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
static void
|
|
ppack_cleanup (void *mutex)
|
|
{
|
|
pthread_mutex_unlock ((pthread_mutex_t *) mutex);
|
|
}
|
|
#endif
|
|
|
|
void
|
|
ppack (FILE * fdes, enum ck_msg_type type, CheckMsg * msg)
|
|
{
|
|
char *buf = NULL;
|
|
int n;
|
|
ssize_t r;
|
|
|
|
n = pack (type, &buf, msg);
|
|
/* Keep it on the safe side to not send too much data. */
|
|
if (n > (CK_MAX_MSG_SIZE / 2))
|
|
eprintf ("Message string too long", __FILE__, __LINE__ - 2);
|
|
|
|
pthread_cleanup_push (ppack_cleanup, &ck_mutex_lock);
|
|
pthread_mutex_lock (&ck_mutex_lock);
|
|
r = fwrite (buf, 1, n, fdes);
|
|
fflush (fdes);
|
|
pthread_mutex_unlock (&ck_mutex_lock);
|
|
pthread_cleanup_pop (0);
|
|
if (r != n)
|
|
eprintf ("Error in call to fwrite:", __FILE__, __LINE__ - 2);
|
|
|
|
free (buf);
|
|
}
|
|
|
|
static int
|
|
read_buf (FILE * fdes, int size, char *buf)
|
|
{
|
|
int n;
|
|
|
|
n = fread (buf, 1, size, fdes);
|
|
|
|
if (ferror (fdes)) {
|
|
eprintf ("Error in call to fread:", __FILE__, __LINE__ - 4);
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
static int
|
|
get_result (char *buf, RcvMsg * rmsg)
|
|
{
|
|
enum ck_msg_type type;
|
|
CheckMsg msg;
|
|
int n;
|
|
|
|
n = upack (buf, &msg, &type);
|
|
if (n == -1)
|
|
eprintf ("Error in call to upack", __FILE__, __LINE__ - 2);
|
|
|
|
if (type == CK_MSG_CTX) {
|
|
CtxMsg *cmsg = (CtxMsg *) & msg;
|
|
|
|
rcvmsg_update_ctx (rmsg, cmsg->ctx);
|
|
} else if (type == CK_MSG_LOC) {
|
|
LocMsg *lmsg = (LocMsg *) & msg;
|
|
|
|
if (rmsg->failctx == CK_CTX_INVALID) {
|
|
rcvmsg_update_loc (rmsg, lmsg->file, lmsg->line);
|
|
}
|
|
free (lmsg->file);
|
|
} else if (type == CK_MSG_FAIL) {
|
|
FailMsg *fmsg = (FailMsg *) & msg;
|
|
|
|
if (rmsg->msg == NULL) {
|
|
rmsg->msg = strdup (fmsg->msg);
|
|
rmsg->failctx = rmsg->lastctx;
|
|
} else {
|
|
/* Skip subsequent failure messages, only happens for CK_NOFORK */
|
|
}
|
|
free (fmsg->msg);
|
|
} else if (type == CK_MSG_DURATION) {
|
|
DurationMsg *cmsg = (DurationMsg *) & msg;
|
|
|
|
rmsg->duration = cmsg->duration;
|
|
} else
|
|
check_type (type, __FILE__, __LINE__);
|
|
|
|
return n;
|
|
}
|
|
|
|
static void
|
|
reset_rcv_test (RcvMsg * rmsg)
|
|
{
|
|
rmsg->test_line = -1;
|
|
rmsg->test_file = NULL;
|
|
}
|
|
|
|
static void
|
|
reset_rcv_fixture (RcvMsg * rmsg)
|
|
{
|
|
rmsg->fixture_line = -1;
|
|
rmsg->fixture_file = NULL;
|
|
}
|
|
|
|
static RcvMsg *
|
|
rcvmsg_create (void)
|
|
{
|
|
RcvMsg *rmsg;
|
|
|
|
rmsg = (RcvMsg *) emalloc (sizeof (RcvMsg));
|
|
rmsg->lastctx = CK_CTX_INVALID;
|
|
rmsg->failctx = CK_CTX_INVALID;
|
|
rmsg->msg = NULL;
|
|
rmsg->duration = -1;
|
|
reset_rcv_test (rmsg);
|
|
reset_rcv_fixture (rmsg);
|
|
return rmsg;
|
|
}
|
|
|
|
void
|
|
rcvmsg_free (RcvMsg * rmsg)
|
|
{
|
|
free (rmsg->fixture_file);
|
|
free (rmsg->test_file);
|
|
free (rmsg->msg);
|
|
free (rmsg);
|
|
}
|
|
|
|
static void
|
|
rcvmsg_update_ctx (RcvMsg * rmsg, enum ck_result_ctx ctx)
|
|
{
|
|
if (rmsg->lastctx != CK_CTX_INVALID) {
|
|
free (rmsg->fixture_file);
|
|
reset_rcv_fixture (rmsg);
|
|
}
|
|
rmsg->lastctx = ctx;
|
|
}
|
|
|
|
static void
|
|
rcvmsg_update_loc (RcvMsg * rmsg, const char *file, int line)
|
|
{
|
|
if (rmsg->lastctx == CK_CTX_TEST) {
|
|
free (rmsg->test_file);
|
|
rmsg->test_line = line;
|
|
rmsg->test_file = strdup (file);
|
|
} else {
|
|
free (rmsg->fixture_file);
|
|
rmsg->fixture_line = line;
|
|
rmsg->fixture_file = strdup (file);
|
|
}
|
|
}
|
|
|
|
RcvMsg *
|
|
punpack (FILE * fdes)
|
|
{
|
|
int nread, nparse, n;
|
|
char *buf;
|
|
RcvMsg *rmsg;
|
|
|
|
rmsg = rcvmsg_create ();
|
|
|
|
/* Allcate a buffer */
|
|
buf = (char *) emalloc (CK_MAX_MSG_SIZE);
|
|
/* Fill the buffer from the file */
|
|
nread = read_buf (fdes, CK_MAX_MSG_SIZE, buf);
|
|
nparse = nread;
|
|
/* While not all parsed */
|
|
while (nparse > 0) {
|
|
/* Parse one message */
|
|
n = get_result (buf, rmsg);
|
|
nparse -= n;
|
|
if (nparse < 0)
|
|
eprintf ("Error in call to get_result", __FILE__, __LINE__ - 3);
|
|
/* Move remaining data in buffer to the beginning */
|
|
memmove (buf, buf + n, nparse);
|
|
/* If EOF has not been seen */
|
|
if (nread > 0) {
|
|
/* Read more data into empty space at end of the buffer */
|
|
nread = read_buf (fdes, n, buf + nparse);
|
|
nparse += nread;
|
|
}
|
|
}
|
|
free (buf);
|
|
|
|
if (rmsg->lastctx == CK_CTX_INVALID) {
|
|
free (rmsg);
|
|
rmsg = NULL;
|
|
}
|
|
|
|
return rmsg;
|
|
}
|