[vlc-commits] [Git][videolan/vlc][master] 3 commits: libvlc.h: ensure the header is correctly exposed to C++

Thomas Guillem (@tguillem) gitlab at videolan.org
Fri Dec 22 13:26:12 UTC 2023



Thomas Guillem pushed to branch master at VideoLAN / VLC


Commits:
1701e2da by Alexandre Janniaux at 2023-12-22T13:00:09+00:00
libvlc.h: ensure the header is correctly exposed to C++

The header is not public but can be used by tests in C++.

- - - - -
6cfbabfc by Alexandre Janniaux at 2023-12-22T13:00:09+00:00
vlc_objects: expose wrappers around vlc_object_create/delete

Using placement new and manual call to the destructor. It ensures that
C++ objects are correctly handled when creating C++ objects through
vlc_object_create<>(), and that their destructors are correctly called
when the (C++) object is destroyed.

According to the C++ draft standard, the vlc_object_t won't get
overwritten by the placement new since (7.1) will apply to the C++
object being allocated and placement-new'ed, which triggers the default
initialization of members, and the default initialization of the
vlc_object_t member enters the (7.3) case since no constructors exists
for the structure. (It's an extern "C" structure).

    To default-initialize an object of type T means:
    (7.1)
    If T is a (possibly cv-qualified) class type ([class]), constructors are considered.
    The applicable constructors are enumerated ([over.match.ctor]), and the best one for the initializer () is chosen through overload resolution ([over.match]).
    The constructor thus selected is called, with an empty argument list, to initialize the object.
    (7.2)
    If T is an array type, each element is default-initialized.
    (7.3)
    Otherwise, no initialization is performed.
    --: https://eel.is/c++draft/dcl.init#general-7

However, it's not possible to use a zero-initializing placement-new
operation.

- - - - -
dbe399b5 by Alexandre Janniaux at 2023-12-22T13:00:09+00:00
objects: add test for C++ wrappers

The test is exposing a stub var_DestroyAll() because object.c is
link-dependant to this symbol, but no variable is created anyway.

It's also checking that the vlc_object_t member doesn't get overwritten.

- - - - -


4 changed files:

- include/vlc_objects.h
- src/Makefile.am
- src/libvlc.h
- + src/misc/objects_cxx_test.cpp


Changes:

=====================================
include/vlc_objects.h
=====================================
@@ -24,6 +24,7 @@
 #define VLC_OBJECTS_H 1
 
 #ifdef __cplusplus
+#include <new>
 extern "C" {
 #endif
 
@@ -314,8 +315,22 @@ template<typename T, typename O> VLC_MALLOC VLC_USED
 static inline T* vlc_object_create(O *obj)
 {
     static_assert(std::is_pointer<T>::value == false, "vlc_object_create can only create objects");
-    return static_cast<T*>(vlc_object_create(VLC_OBJECT(obj), sizeof(T)));
+    void *object = vlc_object_create(VLC_OBJECT(obj), sizeof(T));
+    if (object == nullptr)
+        return nullptr;
+
+    return new(object) T;
 }
+
+#undef vlc_object_delete
+template<typename O>
+static inline void vlc_object_delete(O *obj)
+{
+    if (!std::is_trivially_destructible<O>::value)
+        obj->~O();
+    vlc_object_delete(VLC_OBJECT(obj));
+}
+
 #endif
 
 /** @} */


=====================================
src/Makefile.am
=====================================
@@ -612,6 +612,7 @@ check_PROGRAMS = \
 	test_jaro_winkler \
 	test_list \
 	test_md5 \
+	test_objects_cxx \
 	test_picture_pool \
 	test_sort \
 	test_timer \
@@ -642,6 +643,7 @@ test_interrupt_LDADD = $(LDADD) $(LIBS_libvlccore)
 test_jaro_winkler_SOURCES = test/jaro_winkler.c config/jaro_winkler.c
 test_list_SOURCES = test/list.c
 test_md5_SOURCES = test/md5.c
+test_objects_cxx_SOURCES = misc/objects_cxx_test.cpp misc/objects.c
 test_picture_pool_SOURCES = test/picture_pool.c
 test_sort_SOURCES = test/sort.c
 test_timer_SOURCES = test/timer.c


=====================================
src/libvlc.h
=====================================
@@ -26,6 +26,10 @@
 
 #include <vlc_input_item.h>
 
+# ifdef __cplusplus
+extern "C" {
+# endif
+
 extern const char psz_vlc_changeset[];
 
 typedef struct variable_t variable_t;
@@ -210,4 +214,8 @@ int vlc_MetadataRequest(libvlc_int_t *libvlc, input_item_t *item,
  */
 void var_OptionParse (vlc_object_t *, const char *, bool trusted);
 
+# ifdef __cplusplus
+} // extern "C"
+# endif
+
 #endif


=====================================
src/misc/objects_cxx_test.cpp
=====================================
@@ -0,0 +1,77 @@
+/*****************************************************************************
+ * objects_cxx_test.cpp: vlc_object_t helper tests
+ *****************************************************************************
+ * Copyright (C) 2023 Videlabs
+ *
+ * Authors: Alexandre Janniaux <ajanni at videolabs.io>
+ *
+ * This program 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 program 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <vlc_common.h>
+#include <vlc_objects.h>
+
+#include "../libvlc.h"
+
+extern "C" {
+    void var_DestroyAll(vlc_object_t *) { /* stub */ }
+}
+
+struct ObjectType {
+    vlc_object_t obj;
+    int value = 5;
+    ~ObjectType() { destructor_called = true; }
+    static bool destructor_called;
+};
+bool ObjectType::destructor_called = false;
+
+int main(int argc, char **argv)
+{
+    (void)argc; (void)argv;
+
+    vlc_object_t *root = new vlc_object_t {};
+    int ret = vlc_object_init(root, nullptr, "root");
+    assert(ret == 0);
+
+    struct ObjectType *child = vlc_object_create<ObjectType>(root);
+
+    /* Ensure default constructor have been called. */
+    assert(child->value == 5);
+    assert(ObjectType::destructor_called == false);
+
+    /* No zero-initialization of the object itself. */
+    assert(child->obj.priv != NULL);
+
+    /* Ensure destructor have been called. */
+    vlc_object_delete(child);
+    assert(ObjectType::destructor_called == true);
+    ObjectType::destructor_called = false;
+
+    /* Ensure it's not called for C objects. */
+    ObjectType *child_c = static_cast<ObjectType*>(vlc_object_create(root, sizeof(ObjectType)));
+    assert(child_c->value == 0);
+    vlc_object_delete(VLC_OBJECT(child_c));
+    assert(ObjectType::destructor_called == false);
+
+    vlc_object_deinit(root);
+    delete(root);
+
+    return 0;
+}



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/ca32e6b95fa6dfb2e2cc8b2b946d87df168dffa3...dbe399b593d76d722afadac8272d5939b4c20059

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/ca32e6b95fa6dfb2e2cc8b2b946d87df168dffa3...dbe399b593d76d722afadac8272d5939b4c20059
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list