From 4e55bc83b7837c93e3930c21e59e2f3756c70842 Mon Sep 17 00:00:00 2001 From: Winlin Date: Sat, 26 Apr 2025 00:01:34 -0400 Subject: [PATCH] Support custom deleter for SrsUniquePtr. (#4309) SrsUniquePtr does not support array or object created by malloc, because we only use delete to dispose the resource. You can use a custom function to free the memory allocated by malloc or other allocators. ```cpp char* p = (char*)malloc(1024); SrsUniquePtr ptr(p, your_free_chars); ``` This is used to replace the SrsAutoFreeH. For example: ```cpp addrinfo* r = NULL; SrsAutoFreeH(addrinfo, r, freeaddrinfo); getaddrinfo("127.0.0.1", NULL, &hints, &r); ``` Now, this can be replaced by: ```cpp addrinfo* r = NULL; getaddrinfo("127.0.0.1", NULL, &hints, &r); SrsUniquePtr r2(r, freeaddrinfo); ``` Please aware that there is a slight difference between SrsAutoFreeH and SrsUniquePtr. SrsAutoFreeH will track the address of pointer, while SrsUniquePtr will not. ```cpp addrinfo* r = NULL; SrsAutoFreeH(addrinfo, r, freeaddrinfo); // r will be freed even r is changed later. SrsUniquePtr ptr(r, freeaddrinfo); // crash because r is an invalid pointer. ``` --------- Co-authored-by: Haibo Chen <495810242@qq.com> Co-authored-by: john --- .vscode/settings.json | 20 ++- trunk/3rdparty/st-srs/utest/st_utest.hpp | 73 ----------- trunk/auto/options.sh | 1 + trunk/src/app/srs_app_rtc_source.cpp | 84 ++++++++----- trunk/src/app/srs_app_rtc_source.hpp | 2 + trunk/src/core/srs_core_autofree.hpp | 25 +++- trunk/src/core/srs_core_deprecated.hpp | 150 ++++++++++++----------- trunk/src/kernel/srs_kernel_mp4.cpp | 30 +++-- trunk/src/kernel/srs_kernel_mp4.hpp | 3 + trunk/src/kernel/srs_kernel_utility.cpp | 6 +- trunk/src/main/srs_main_mp4_parser.cpp | 12 +- trunk/src/protocol/srs_protocol_srt.cpp | 8 +- trunk/src/protocol/srs_protocol_st.cpp | 22 ++-- trunk/src/utest/srs_utest_core.cpp | 123 ++++++++++++++++++- trunk/src/utest/srs_utest_protocol.cpp | 4 +- trunk/src/utest/srs_utest_rtmp.cpp | 2 +- trunk/src/utest/srs_utest_service.cpp | 48 ++++---- trunk/src/utest/srs_utest_st.cpp | 2 +- 18 files changed, 362 insertions(+), 253 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 0d9dbf97b..58eb63a36 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,23 @@ { "cmake.sourceDirectory": "${workspaceFolder}/trunk/ide/srs_clion", "cmake.buildDirectory": "${workspaceFolder}/trunk/ide/vscode-build", - "cmake.configureOnOpen": false + "cmake.configureOnOpen": false, + "files.associations": { + "vector": "cpp", + "__hash_table": "cpp", + "__split_buffer": "cpp", + "__tree": "cpp", + "array": "cpp", + "bitset": "cpp", + "deque": "cpp", + "initializer_list": "cpp", + "list": "cpp", + "map": "cpp", + "queue": "cpp", + "set": "cpp", + "stack": "cpp", + "string": "cpp", + "string_view": "cpp", + "unordered_map": "cpp" + } } diff --git a/trunk/3rdparty/st-srs/utest/st_utest.hpp b/trunk/3rdparty/st-srs/utest/st_utest.hpp index 978d3f97e..7b6e5d4e2 100644 --- a/trunk/3rdparty/st-srs/utest/st_utest.hpp +++ b/trunk/3rdparty/st-srs/utest/st_utest.hpp @@ -50,78 +50,5 @@ extern std::ostream& operator<<(std::ostream& out, const ErrorObject* err); #include -// To free the instance in the current scope, for instance, MyClass* ptr, -// which is a ptr and this class will: -// 1. free the ptr. -// 2. set ptr to NULL. -// -// Usage: -// MyClass* po = new MyClass(); -// // ...... use po -// SrsAutoFree(MyClass, po); -// -// Usage for array: -// MyClass** pa = new MyClass*[size]; -// // ....... use pa -// SrsAutoFreeA(MyClass*, pa); -// -// @remark the MyClass can be basic type, for instance, SrsAutoFreeA(char, pstr), -// where the char* pstr = new char[size]. -// To delete object. -#define SrsAutoFree(className, instance) \ - impl_SrsAutoFree _auto_free_##instance(&instance, false, false, NULL) -// To delete array. -#define SrsAutoFreeA(className, instance) \ - impl_SrsAutoFree _auto_free_array_##instance(&instance, true, false, NULL) -// Use free instead of delete. -#define SrsAutoFreeF(className, instance) \ - impl_SrsAutoFree _auto_free_##instance(&instance, false, true, NULL) -// Use hook instead of delete. -#define SrsAutoFreeH(className, instance, hook) \ - impl_SrsAutoFree _auto_free_##instance(&instance, false, false, hook) -// The template implementation. -template -class impl_SrsAutoFree -{ -private: - T** ptr; - bool is_array; - bool _use_free; - void (*_hook)(T*); -public: - // If use_free, use free(void*) to release the p. - // If specified hook, use hook(p) to release it. - // Use delete to release p, or delete[] if p is an array. - impl_SrsAutoFree(T** p, bool array, bool use_free, void (*hook)(T*)) { - ptr = p; - is_array = array; - _use_free = use_free; - _hook = hook; - } - - virtual ~impl_SrsAutoFree() { - if (ptr == NULL || *ptr == NULL) { - return; - } - - if (_use_free) { - free(*ptr); - } else if (_hook) { - _hook(*ptr); - } else { - if (is_array) { - delete[] *ptr; - } else { - delete *ptr; - } - } - - *ptr = NULL; - } -}; - -// The time unit in ms, for example 100 * SRS_UTIME_MILLISECONDS means 100ms. -#define SRS_UTIME_MILLISECONDS 1000 - #endif diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh index e7a512909..64501f552 100755 --- a/trunk/auto/options.sh +++ b/trunk/auto/options.sh @@ -360,6 +360,7 @@ function parse_user_option() { --gmp) SRS_GPERF_MP=$(switch2value $value) ;; --gcp) SRS_GPERF_CP=$(switch2value $value) ;; --gprof) SRS_GPROF=$(switch2value $value) ;; + --asan) SRS_SANITIZER=$(switch2value $value) ;; --sanitizer) SRS_SANITIZER=$(switch2value $value) ;; --sanitizer-static) SRS_SANITIZER_STATIC=$(switch2value $value) ;; --sanitizer-log) SRS_SANITIZER_LOG=$(switch2value $value) ;; diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index 43fde7845..ddee477c4 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -1638,41 +1638,15 @@ srs_error_t SrsRtcFrameBuilder::packet_video_key_frame(SrsRtpPacket* pkt) return srs_error_new(ERROR_RTC_RTP_MUXER, "no sps or pps in stap-a rtp. sps: %p, pps:%p", sps, pps); } - // Reset SPS/PPS cache, ensuring that the next SPS/PPS will be handled when both are received. - // Note that we should use SrsAutoFree to set the ptr to NULL. - SrsAutoFree(SrsRtpPacket, obs_whip_sps_); - SrsAutoFree(SrsRtpPacket, obs_whip_pps_); + // Packet SPS/PPS to RTMP keyframe. + err = packet_sps_pps(pkt, sps, pps); - // h264 raw to h264 packet. - std::string sh; - SrsUniquePtr avc(new SrsRawH264Stream()); - - if ((err = avc->mux_sequence_header(string(sps->bytes, sps->size), string(pps->bytes, pps->size), sh)) != srs_success) { - return srs_error_wrap(err, "mux sequence header"); - } - - // h264 packet to flv packet. - char* flv = NULL; - int nb_flv = 0; - if ((err = avc->mux_avc2flv(sh, SrsVideoAvcFrameTypeKeyFrame, SrsVideoAvcFrameTraitSequenceHeader, pkt->get_avsync_time(), - pkt->get_avsync_time(), &flv, &nb_flv)) != srs_success) { - return srs_error_wrap(err, "avc to flv"); - } - - SrsMessageHeader header; - header.initialize_video(nb_flv, pkt->get_avsync_time(), 1); - SrsCommonMessage rtmp; - if ((err = rtmp.create(&header, flv, nb_flv)) != srs_success) { - return srs_error_wrap(err, "create rtmp"); - } - - SrsSharedPtrMessage msg; - if ((err = msg.create(&rtmp)) != srs_success) { - return srs_error_wrap(err, "create message"); - } - - if ((err = bridge_->on_frame(&msg)) != srs_success) { - return err; + // Always reset the SPS/PPS cache after used it. + srs_freep(obs_whip_sps_); + srs_freep(obs_whip_pps_); + + if (err != srs_success) { + return srs_error_wrap(err, "packet sps/pps"); } } @@ -1729,6 +1703,48 @@ srs_error_t SrsRtcFrameBuilder::packet_video_key_frame(SrsRtpPacket* pkt) return err; } +srs_error_t SrsRtcFrameBuilder::packet_sps_pps(SrsRtpPacket* pkt, SrsSample* sps, SrsSample* pps) +{ + srs_error_t err = srs_success; + + // h264 raw to h264 packet. + std::string sh; + SrsUniquePtr avc(new SrsRawH264Stream()); + + string sps2 = string(sps->bytes, sps->size); + string pps2 = string(pps->bytes, pps->size); + if ((err = avc->mux_sequence_header(sps2, pps2, sh)) != srs_success) { + return srs_error_wrap(err, "mux sequence header"); + } + + // h264 packet to flv packet. + char* flv = NULL; + int nb_flv = 0; + if ((err = avc->mux_avc2flv(sh, SrsVideoAvcFrameTypeKeyFrame, + SrsVideoAvcFrameTraitSequenceHeader, pkt->get_avsync_time(), + pkt->get_avsync_time(), &flv, &nb_flv)) != srs_success) { + return srs_error_wrap(err, "avc to flv"); + } + + SrsMessageHeader header; + header.initialize_video(nb_flv, pkt->get_avsync_time(), 1); + SrsCommonMessage rtmp; + if ((err = rtmp.create(&header, flv, nb_flv)) != srs_success) { + return srs_error_wrap(err, "create rtmp"); + } + + SrsSharedPtrMessage msg; + if ((err = msg.create(&rtmp)) != srs_success) { + return srs_error_wrap(err, "create message"); + } + + if ((err = bridge_->on_frame(&msg)) != srs_success) { + return err; + } + + return err; +} + srs_error_t SrsRtcFrameBuilder::packet_video_rtmp(const uint16_t start, const uint16_t end) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_rtc_source.hpp b/trunk/src/app/srs_app_rtc_source.hpp index 7c813a97a..3efe3904d 100644 --- a/trunk/src/app/srs_app_rtc_source.hpp +++ b/trunk/src/app/srs_app_rtc_source.hpp @@ -356,6 +356,8 @@ private: private: srs_error_t packet_video(SrsRtpPacket* pkt); srs_error_t packet_video_key_frame(SrsRtpPacket* pkt); + srs_error_t packet_sps_pps(SrsRtpPacket* pkt, SrsSample* sps, SrsSample* pps); +private: inline uint16_t cache_index(uint16_t current_sn) { return current_sn % s_cache_size; } diff --git a/trunk/src/core/srs_core_autofree.hpp b/trunk/src/core/srs_core_autofree.hpp index 211d2daae..9736d193a 100644 --- a/trunk/src/core/srs_core_autofree.hpp +++ b/trunk/src/core/srs_core_autofree.hpp @@ -16,23 +16,36 @@ // SrsUniquePtr ptr(new MyClass()); // ptr->do_something(); // -// Note that the ptr should be initialized before use it, or it will crash if not set, for example: +// Note that the p should be initialized before use it, or it will crash if not set, for example: // Myclass* p; // SrsUniquePtr ptr(p); // crash because p is an invalid pointer. // // Note that do not support array or object created by malloc, because we only use delete to dispose -// the resource. +// the resource. You can use a custom function to free the memory allocated by malloc or other +// allocators. +// char* p = (char*)malloc(1024); +// SrsUniquePtr ptr(p, your_free_chars); +// Or to free a specific object: +// addrinfo* r = NULL; +// getaddrinfo("127.0.0.1", NULL, &hints, &r); +// SrsUniquePtr ptr(r, freeaddrinfo); template class SrsUniquePtr { private: T* ptr_; + void (*deleter_)(T*); public: - SrsUniquePtr(T* ptr = NULL) { + SrsUniquePtr(T* ptr = NULL, void (*deleter)(T*) = NULL) { ptr_ = ptr; + deleter_ = deleter; } virtual ~SrsUniquePtr() { - delete ptr_; + if (!deleter_) { + delete ptr_; + } else { + deleter_(ptr_); + } } public: // Get the object. @@ -68,6 +81,10 @@ private: // Usage: // SrsUniquePtr ptr(new MyClass[10]); // ptr[0]->do_something(); +// +// Note that the p should be initialized before use it, or it will crash if not set, for example: +// Myclass* p; +// SrsUniquePtr ptr(p); // crash because p is an invalid pointer. template class SrsUniquePtr { diff --git a/trunk/src/core/srs_core_deprecated.hpp b/trunk/src/core/srs_core_deprecated.hpp index 1cc912117..966f3449f 100644 --- a/trunk/src/core/srs_core_deprecated.hpp +++ b/trunk/src/core/srs_core_deprecated.hpp @@ -11,85 +11,93 @@ #include -// Note that the SrsAutoFree is deprecated, please use SrsUniquePtr instead. +// Note that the SrsAutoFree is deprecated, please use SrsUniquePtr instead. For example: +// MyClass* p = new MyClass(); +// SrsAutoFree(MyClass, p); +// This can be replaced by: +// SrsUniquePtr p(new MyClass()); // -// Note: Please use SrsUniquePtr if possible. Please aware that there is a slight difference between SrsAutoFree -// and SrsUniquePtr. SrsAutoFree will track the address of pointer, while SrsUniquePtr will not. +// Note: Please aware that there is a slight difference between SrsAutoFree and SrsUniquePtr. +// SrsAutoFree will track the address of pointer, while SrsUniquePtr will not. // MyClass* p; // SrsAutoFree(MyClass, p); // p will be freed even p is changed later. // SrsUniquePtr ptr(p); // crash because p is an invalid pointer. // -// The auto free helper, which is actually the unique ptr, without the move feature, -// see https://github.com/ossrs/srs/discussions/3667#discussioncomment-8969107 -// -// To free the instance in the current scope, for instance, MyClass* ptr, -// which is a ptr and this class will: -// 1. free the ptr. -// 2. set ptr to NULL. -// -// Usage: -// MyClass* po = new MyClass(); -// // ...... use po -// SrsAutoFree(MyClass, po); -// -// Usage for array: +// See https://github.com/ossrs/srs/discussions/3667#discussioncomment-8969107 for more details. +//#define SrsAutoFree(className, instance) \ +// impl_SrsAutoFree _auto_free_##instance(&instance, false, false, NULL) +// To delete array. Please use SrsUniquePtr instead. For example: // MyClass** pa = new MyClass*[size]; -// // ....... use pa // SrsAutoFreeA(MyClass*, pa); +// This can be replaced by: +// SrsUniquePtr pa(new MyClass[10]); // -// @remark the MyClass can be basic type, for instance, SrsAutoFreeA(char, pstr), -// where the char* pstr = new char[size]. -// To delete object. -#define SrsAutoFree(className, instance) \ - impl_SrsAutoFree _auto_free_##instance(&instance, false, false, NULL) -// To delete array. -#define SrsAutoFreeA(className, instance) \ - impl_SrsAutoFree _auto_free_array_##instance(&instance, true, false, NULL) -// Use free instead of delete. -#define SrsAutoFreeF(className, instance) \ - impl_SrsAutoFree _auto_free_##instance(&instance, false, true, NULL) -// Use hook instead of delete. -#define SrsAutoFreeH(className, instance, hook) \ - impl_SrsAutoFree _auto_free_##instance(&instance, false, false, hook) +// Note: Please aware that there is a slight difference between SrsAutoFreeA and SrsUniquePtr. +// SrsAutoFreeA will track the address of pointer, while SrsUniquePtr will not. +// MyClass** pa; +// SrsAutoFreeA(MyClass*, pa); // pa will be freed even pa is changed later. +// SrsUniquePtr ptr(pa); // crash because pa is an invalid pointer. +// +// See https://github.com/ossrs/srs/discussions/3667#discussioncomment-8969107 for more details. +//#define SrsAutoFreeA(className, instance) \ +// impl_SrsAutoFree _auto_free_array_##instance(&instance, true, false, NULL) +// Use hook instead of delete. Please use SrsUniquePtr instead. For example: +// addrinfo* r = NULL; +// SrsAutoFreeH(addrinfo, r, freeaddrinfo); +// getaddrinfo("127.0.0.1", NULL, &hints, &r); +// This can be replaced by: +// addrinfo* r = NULL; +// getaddrinfo("127.0.0.1", NULL, &hints, &r); +// SrsUniquePtr ptr(r, freeaddrinfo); +// +// Note: Please aware that there is a slight difference between SrsAutoFreeH and SrsUniquePtr. +// SrsAutoFreeH will track the address of pointer, while SrsUniquePtr will not. +// addrinfo* r = NULL; +// SrsAutoFreeH(addrinfo, r, freeaddrinfo); // r will be freed even r is changed later. +// SrsUniquePtr ptr(r, freeaddrinfo); // crash because r is an invalid pointer. +// +// See https://github.com/ossrs/srs/discussions/3667#discussioncomment-8969107 for more details. +//#define SrsAutoFreeH(className, instance, hook) \ +// impl_SrsAutoFree _auto_free_##instance(&instance, false, false, hook) // The template implementation. -template -class impl_SrsAutoFree -{ -private: - T** ptr; - bool is_array; - bool _use_free; - void (*_hook)(T*); -public: - // If use_free, use free(void*) to release the p. - // If specified hook, use hook(p) to release it. - // Use delete to release p, or delete[] if p is an array. - impl_SrsAutoFree(T** p, bool array, bool use_free, void (*hook)(T*)) { - ptr = p; - is_array = array; - _use_free = use_free; - _hook = hook; - } - - virtual ~impl_SrsAutoFree() { - if (ptr == NULL || *ptr == NULL) { - return; - } - - if (_use_free) { - free(*ptr); - } else if (_hook) { - _hook(*ptr); - } else { - if (is_array) { - delete[] *ptr; - } else { - delete *ptr; - } - } - - *ptr = NULL; - } -}; +//template +//class impl_SrsAutoFree +//{ +//private: +// T** ptr; +// bool is_array; +// bool _use_free; +// void (*_hook)(T*); +//public: +// // If use_free, use free(void*) to release the p. +// // If specified hook, use hook(p) to release it. +// // Use delete to release p, or delete[] if p is an array. +// impl_SrsAutoFree(T** p, bool array, bool use_free, void (*hook)(T*)) { +// ptr = p; +// is_array = array; +// _use_free = use_free; +// _hook = hook; +// } +// +// virtual ~impl_SrsAutoFree() { +// if (ptr == NULL || *ptr == NULL) { +// return; +// } +// +// if (_use_free) { +// free(*ptr); +// } else if (_hook) { +// _hook(*ptr); +// } else { +// if (is_array) { +// delete[] *ptr; +// } else { +// delete *ptr; +// } +// } +// +// *ptr = NULL; +// } +//}; #endif diff --git a/trunk/src/kernel/srs_kernel_mp4.cpp b/trunk/src/kernel/srs_kernel_mp4.cpp index afbc07a8c..9a4ad4773 100644 --- a/trunk/src/kernel/srs_kernel_mp4.cpp +++ b/trunk/src/kernel/srs_kernel_mp4.cpp @@ -5315,9 +5315,21 @@ srs_error_t SrsMp4BoxReader::read(SrsSimpleStream* stream, SrsMp4Box** ppbox) srs_error_t err = srs_success; SrsMp4Box* box = NULL; - // Note that we should use SrsAutoFree to free the ptr which is set later. - SrsAutoFree(SrsMp4Box, box); + if ((err = do_read(stream, box)) == srs_success) { + *ppbox = box; + return err; + } + // When error, free the created box. + srs_freep(box); + + return err; +} + +srs_error_t SrsMp4BoxReader::do_read(SrsSimpleStream* stream, SrsMp4Box*& box) +{ + srs_error_t err = srs_success; + while (true) { // For the first time to read the box, maybe it's a basic box which is only 4bytes header. // When we disconvery the real box, we know the size of the whole box, then read again and decode it. @@ -5357,11 +5369,6 @@ srs_error_t SrsMp4BoxReader::read(SrsSimpleStream* stream, SrsMp4Box** ppbox) continue; } - if (err == srs_success) { - *ppbox = box; - box = NULL; - } - break; } @@ -5651,18 +5658,17 @@ srs_error_t SrsMp4Decoder::load_next_box(SrsMp4Box** ppbox, uint32_t required_bo while (true) { SrsMp4Box* box = NULL; - // Note that we should use SrsAutoFree to free the ptr which is set later. - SrsAutoFree(SrsMp4Box, box); - if ((err = do_load_next_box(&box, required_box_type)) != srs_success) { return srs_error_wrap(err, "load box"); } if (!required_box_type || (uint32_t)box->type == required_box_type) { *ppbox = box; - box = NULL; - break; + return err; } + + // Free the box is not matched the required type. + srs_freep(box); } return err; diff --git a/trunk/src/kernel/srs_kernel_mp4.hpp b/trunk/src/kernel/srs_kernel_mp4.hpp index 39fd506d6..c4b1fdf53 100644 --- a/trunk/src/kernel/srs_kernel_mp4.hpp +++ b/trunk/src/kernel/srs_kernel_mp4.hpp @@ -1963,6 +1963,9 @@ public: public: // Read a MP4 box to pbox, the stream is fill with the bytes of box to decode. virtual srs_error_t read(SrsSimpleStream* stream, SrsMp4Box** ppbox); +private: + srs_error_t do_read(SrsSimpleStream* stream, SrsMp4Box*& box); +public: // Skip the box from stream, and skip in file if need. virtual srs_error_t skip(SrsMp4Box* box, SrsSimpleStream* stream); }; diff --git a/trunk/src/kernel/srs_kernel_utility.cpp b/trunk/src/kernel/srs_kernel_utility.cpp index 085b1ede5..6bf300b9c 100644 --- a/trunk/src/kernel/srs_kernel_utility.cpp +++ b/trunk/src/kernel/srs_kernel_utility.cpp @@ -156,11 +156,11 @@ string srs_dns_resolve(string host, int& family) memset(&hints, 0, sizeof(hints)); hints.ai_family = family; - addrinfo* r = NULL; - SrsAutoFreeH(addrinfo, r, freeaddrinfo); - if(getaddrinfo(host.c_str(), NULL, &hints, &r)) { + addrinfo* r_raw = NULL; + if(getaddrinfo(host.c_str(), NULL, &hints, &r_raw)) { return ""; } + SrsUniquePtr r(r_raw, freeaddrinfo); char shost[64]; memset(shost, 0, sizeof(shost)); diff --git a/trunk/src/main/srs_main_mp4_parser.cpp b/trunk/src/main/srs_main_mp4_parser.cpp index 27cbc3623..37fa3a5e7 100644 --- a/trunk/src/main/srs_main_mp4_parser.cpp +++ b/trunk/src/main/srs_main_mp4_parser.cpp @@ -60,23 +60,23 @@ srs_error_t parse(std::string mp4_file, bool verbose) fprintf(stderr, "\n%s\n", mp4_file.c_str()); while (true) { - SrsMp4Box* box = NULL; - // Note that we should use SrsAutoFree to free the ptr which is set later. - SrsAutoFree(SrsMp4Box, box); - - if ((err = br.read(stream.get(), &box)) != srs_success) { + SrsMp4Box* box_raw = NULL; + if ((err = br.read(stream.get(), &box_raw)) != srs_success) { if (srs_error_code(err) == ERROR_SYSTEM_FILE_EOF) { fprintf(stderr, "\n"); } return srs_error_wrap(err, "read box"); } + // Should use unique pointer after box is created. + SrsUniquePtr box(box_raw); + SrsUniquePtr buffer(new SrsBuffer(stream->bytes(), stream->length())); if ((err = box->decode(buffer.get())) != srs_success) { return srs_error_wrap(err, "decode box"); } - if ((err = br.skip(box, stream.get())) != srs_success) { + if ((err = br.skip(box.get(), stream.get())) != srs_success) { return srs_error_wrap(err, "skip box"); } diff --git a/trunk/src/protocol/srs_protocol_srt.cpp b/trunk/src/protocol/srs_protocol_srt.cpp index 4535ee6d4..84e3628fd 100644 --- a/trunk/src/protocol/srs_protocol_srt.cpp +++ b/trunk/src/protocol/srs_protocol_srt.cpp @@ -198,14 +198,14 @@ srs_error_t srs_srt_listen(srs_srt_t srt_fd, std::string ip, int port) hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_NUMERICHOST; - addrinfo* r = NULL; - SrsAutoFreeH(addrinfo, r, freeaddrinfo); - if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r)) { + addrinfo* r_raw = NULL; + if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r_raw)) { return srs_error_new(ERROR_SYSTEM_IP_INVALID, "getaddrinfo hints=(%d,%d,%d)", hints.ai_family, hints.ai_socktype, hints.ai_flags); } + SrsUniquePtr r(r_raw, freeaddrinfo); - if ((err = do_srs_srt_listen(srt_fd, r)) != srs_success) { + if ((err = do_srs_srt_listen(srt_fd, r.get())) != srs_success) { srt_close(srt_fd); return srs_error_wrap(err, "srt_fd=%d", srt_fd); } diff --git a/trunk/src/protocol/srs_protocol_st.cpp b/trunk/src/protocol/srs_protocol_st.cpp index 2b2b9542d..944926c70 100644 --- a/trunk/src/protocol/srs_protocol_st.cpp +++ b/trunk/src/protocol/srs_protocol_st.cpp @@ -213,11 +213,11 @@ srs_error_t srs_tcp_connect(string server, int port, srs_utime_t tm, srs_netfd_t hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - addrinfo* r = NULL; - SrsAutoFreeH(addrinfo, r, freeaddrinfo); - if(getaddrinfo(server.c_str(), sport, (const addrinfo*)&hints, &r)) { + addrinfo* r_raw = NULL; + if(getaddrinfo(server.c_str(), sport, (const addrinfo*)&hints, &r_raw)) { return srs_error_new(ERROR_SYSTEM_IP_INVALID, "get address info"); } + SrsUniquePtr r(r_raw, freeaddrinfo); int sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol); if(sock == -1){ @@ -291,12 +291,12 @@ srs_error_t srs_tcp_listen(std::string ip, int port, srs_netfd_t* pfd) hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_NUMERICHOST; - addrinfo* r = NULL; - SrsAutoFreeH(addrinfo, r, freeaddrinfo); - if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r)) { + addrinfo* r_raw = NULL; + if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r_raw)) { return srs_error_new(ERROR_SYSTEM_IP_INVALID, "getaddrinfo hints=(%d,%d,%d)", hints.ai_family, hints.ai_socktype, hints.ai_flags); } + SrsUniquePtr r(r_raw, freeaddrinfo); int fd = 0; if ((fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) == -1) { @@ -304,7 +304,7 @@ srs_error_t srs_tcp_listen(std::string ip, int port, srs_netfd_t* pfd) r->ai_family, r->ai_socktype, r->ai_protocol); } - if ((err = do_srs_tcp_listen(fd, r, pfd)) != srs_success) { + if ((err = do_srs_tcp_listen(fd, r.get(), pfd)) != srs_success) { ::close(fd); return srs_error_wrap(err, "fd=%d", fd); } @@ -353,12 +353,12 @@ srs_error_t srs_udp_listen(std::string ip, int port, srs_netfd_t* pfd) hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_NUMERICHOST; - addrinfo* r = NULL; - SrsAutoFreeH(addrinfo, r, freeaddrinfo); - if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r)) { + addrinfo* r_raw = NULL; + if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r_raw)) { return srs_error_new(ERROR_SYSTEM_IP_INVALID, "getaddrinfo hints=(%d,%d,%d)", hints.ai_family, hints.ai_socktype, hints.ai_flags); } + SrsUniquePtr r(r_raw, freeaddrinfo); int fd = 0; if ((fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) == -1) { @@ -366,7 +366,7 @@ srs_error_t srs_udp_listen(std::string ip, int port, srs_netfd_t* pfd) r->ai_family, r->ai_socktype, r->ai_protocol); } - if ((err = do_srs_udp_listen(fd, r, pfd)) != srs_success) { + if ((err = do_srs_udp_listen(fd, r.get(), pfd)) != srs_success) { ::close(fd); return srs_error_wrap(err, "fd=%d", fd); } diff --git a/trunk/src/utest/srs_utest_core.cpp b/trunk/src/utest/srs_utest_core.cpp index c00d611a9..838d73b8a 100644 --- a/trunk/src/utest/srs_utest_core.cpp +++ b/trunk/src/utest/srs_utest_core.cpp @@ -17,12 +17,6 @@ VOID TEST(CoreAutoFreeTest, Free) char* data = new char[32]; srs_freepa(data); EXPECT_TRUE(data == NULL); - - if (true) { - data = new char[32]; - SrsAutoFreeA(char, data); - } - EXPECT_TRUE(data == NULL); } VOID TEST(CoreMacroseTest, Check) @@ -489,3 +483,120 @@ VOID TEST(CoreSmartPtr, UniquePtrArray) EXPECT_EQ(100, *ptr); } +#ifndef _WIN32 +#include +#endif + +void mock_free_chars(char* p) { + free(p); +} + +VOID TEST(CoreSmartPtr, UniquePtrDeleterExample) +{ + if (true) { + char* p = (char*)malloc(1024); + SrsUniquePtr ptr(p, mock_free_chars); + } + + if (true) { + addrinfo* r = NULL; + getaddrinfo("127.0.0.1", NULL, NULL, &r); + SrsUniquePtr ptr(r, freeaddrinfo); + } +} + +class MockSlice +{ +public: + const char* bytes_; +public: + MockSlice(const char* bytes) { + bytes_ = bytes; + } + virtual ~MockSlice() { + } +public: + static void deleter(MockSlice* p) { + p->bytes_ = NULL; + } +}; + +VOID TEST(CoreSmartPtr, UniquePtrDeleterSlice) +{ + MockSlice p("Hello"); + EXPECT_TRUE(p.bytes_ != NULL); + + if (true) { + SrsUniquePtr ptr(&p, MockSlice::deleter); + } + EXPECT_TRUE(p.bytes_ == NULL); +} + +class MockSpecialPacket +{ +public: + char* bytes_; + int size_; +public: + MockSpecialPacket(char* bytes, int size) { + bytes_ = bytes; + size_ = size; + } + virtual ~MockSpecialPacket() { + srs_freep(bytes_); + } +public: + static void deleter(vector* pkts) { + vector::iterator it; + for (it = pkts->begin(); it != pkts->end(); ++it) { + MockSpecialPacket* pkt = *it; + srs_freep(pkt); + } + pkts->clear(); + } +}; + +VOID TEST(CoreSmartPtr, UniquePtrDeleterVector) +{ + vector pkts; + for (int i = 0; i < 10; i++) { + char* bytes = new char[1024]; + MockSpecialPacket* pkt = new MockSpecialPacket(bytes, 1024); + pkts.push_back(pkt); + } + EXPECT_EQ(10, (int)pkts.size()); + + if (true) { + SrsUniquePtr> ptr(&pkts, MockSpecialPacket::deleter); + } + EXPECT_EQ(0, (int)pkts.size()); +} + +class MockMalloc +{ +public: + const char* bytes_; +public: + MockMalloc(int size) { + bytes_ = (char*)malloc(size); + } + virtual ~MockMalloc() { + } +public: + static void deleter(MockMalloc* p) { + free((void*)p->bytes_); + p->bytes_ = NULL; + } +}; + +VOID TEST(CoreSmartPtr, UniquePtrDeleterMalloc) +{ + MockMalloc p(1024); + EXPECT_TRUE(p.bytes_ != NULL); + + if (true) { + SrsUniquePtr ptr(&p, MockMalloc::deleter); + } + EXPECT_TRUE(p.bytes_ == NULL); +} + diff --git a/trunk/src/utest/srs_utest_protocol.cpp b/trunk/src/utest/srs_utest_protocol.cpp index f1f3d7651..b03a0b867 100644 --- a/trunk/src/utest/srs_utest_protocol.cpp +++ b/trunk/src/utest/srs_utest_protocol.cpp @@ -626,7 +626,7 @@ VOID TEST(ProtocolMsgArrayTest, MessageArray) SrsMessageArray arr(3); SrsMessageArray* parr = &arr; - SrsAutoFreeH(SrsMessageArray, parr, srs_utest_free_message_array); + SrsUniquePtr parr2(parr, srs_utest_free_message_array); arr.msgs[0] = msg.copy(); EXPECT_EQ(1, msg.count()); @@ -643,7 +643,7 @@ VOID TEST(ProtocolMsgArrayTest, MessageArray) SrsMessageArray arr(3); SrsMessageArray* parr = &arr; - SrsAutoFreeH(SrsMessageArray, parr, srs_utest_free_message_array); + SrsUniquePtr parr2(parr, srs_utest_free_message_array); arr.msgs[0] = msg.copy(); EXPECT_EQ(1, msg.count()); diff --git a/trunk/src/utest/srs_utest_rtmp.cpp b/trunk/src/utest/srs_utest_rtmp.cpp index 7661f1316..eba72eedb 100644 --- a/trunk/src/utest/srs_utest_rtmp.cpp +++ b/trunk/src/utest/srs_utest_rtmp.cpp @@ -2999,7 +2999,7 @@ VOID TEST(ProtocolRTMPTest, OthersAll) SrsMessageArray h(10); SrsMessageArray* parr = &h; - SrsAutoFreeH(SrsMessageArray, parr, srs_utest_free_message_array); + SrsUniquePtr parr2(parr, srs_utest_free_message_array); h.msgs[0] = new SrsSharedPtrMessage(); h.msgs[1] = new SrsSharedPtrMessage(); diff --git a/trunk/src/utest/srs_utest_service.cpp b/trunk/src/utest/srs_utest_service.cpp index b46b8a1ae..ab6875ec5 100644 --- a/trunk/src/utest/srs_utest_service.cpp +++ b/trunk/src/utest/srs_utest_service.cpp @@ -1118,9 +1118,9 @@ VOID TEST(TCPServerTest, CoverUtility) memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; - addrinfo* r = NULL; - SrsAutoFreeH(addrinfo, r, freeaddrinfo); - ASSERT_TRUE(!getaddrinfo("127.0.0.1", NULL, &hints, &r)); + addrinfo* r_raw = NULL; + ASSERT_TRUE(!getaddrinfo("127.0.0.1", NULL, &hints, &r_raw)); + SrsUniquePtr r(r_raw, freeaddrinfo); EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr)); } @@ -1131,9 +1131,9 @@ VOID TEST(TCPServerTest, CoverUtility) memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; - addrinfo* r = NULL; - SrsAutoFreeH(addrinfo, r, freeaddrinfo); - ASSERT_TRUE(!getaddrinfo("192.168.0.1", NULL, &hints, &r)); + addrinfo* r_raw = NULL; + ASSERT_TRUE(!getaddrinfo("192.168.0.1", NULL, &hints, &r_raw)); + SrsUniquePtr r(r_raw, freeaddrinfo); EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr)); } @@ -1176,9 +1176,9 @@ VOID TEST(TCPServerTest, CoverUtility) memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; - addrinfo* r = NULL; - SrsAutoFreeH(addrinfo, r, freeaddrinfo); - ASSERT_TRUE(!getaddrinfo("2001:da8:6000:291:21f:d0ff:fed4:928c", NULL, &hints, &r)); + addrinfo* r_raw = NULL; + ASSERT_TRUE(!getaddrinfo("2001:da8:6000:291:21f:d0ff:fed4:928c", NULL, &hints, &r_raw)); + SrsUniquePtr r(r_raw, freeaddrinfo); EXPECT_TRUE(srs_net_device_is_internet((sockaddr*)r->ai_addr)); } @@ -1187,9 +1187,9 @@ VOID TEST(TCPServerTest, CoverUtility) memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; - addrinfo* r = NULL; - SrsAutoFreeH(addrinfo, r, freeaddrinfo); - ASSERT_TRUE(!getaddrinfo("3ffe:dead:beef::1", NULL, &hints, &r)); + addrinfo* r_raw = NULL; + ASSERT_TRUE(!getaddrinfo("3ffe:dead:beef::1", NULL, &hints, &r_raw)); + SrsUniquePtr r(r_raw, freeaddrinfo); EXPECT_TRUE(srs_net_device_is_internet((sockaddr*)r->ai_addr)); } @@ -1200,9 +1200,9 @@ VOID TEST(TCPServerTest, CoverUtility) memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; - addrinfo* r = NULL; - SrsAutoFreeH(addrinfo, r, freeaddrinfo); - ASSERT_TRUE(!getaddrinfo("::", NULL, &hints, &r)); + addrinfo* r_raw = NULL; + ASSERT_TRUE(!getaddrinfo("::", NULL, &hints, &r_raw)); + SrsUniquePtr r(r_raw, freeaddrinfo); EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr)); } @@ -1213,9 +1213,9 @@ VOID TEST(TCPServerTest, CoverUtility) memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; - addrinfo* r = NULL; - SrsAutoFreeH(addrinfo, r, freeaddrinfo); - ASSERT_TRUE(!getaddrinfo("fec0::", NULL, &hints, &r)); + addrinfo* r_raw = NULL; + ASSERT_TRUE(!getaddrinfo("fec0::", NULL, &hints, &r_raw)); + SrsUniquePtr r(r_raw, freeaddrinfo); EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr)); } @@ -1226,9 +1226,9 @@ VOID TEST(TCPServerTest, CoverUtility) memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; - addrinfo* r = NULL; - SrsAutoFreeH(addrinfo, r, freeaddrinfo); - ASSERT_TRUE(!getaddrinfo("FE80::", NULL, &hints, &r)); + addrinfo* r_raw = NULL; + ASSERT_TRUE(!getaddrinfo("FE80::", NULL, &hints, &r_raw)); + SrsUniquePtr r(r_raw, freeaddrinfo); EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr)); } @@ -1239,9 +1239,9 @@ VOID TEST(TCPServerTest, CoverUtility) memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; - addrinfo* r = NULL; - SrsAutoFreeH(addrinfo, r, freeaddrinfo); - ASSERT_TRUE(!getaddrinfo("::1", NULL, &hints, &r)); + addrinfo* r_raw = NULL; + ASSERT_TRUE(!getaddrinfo("::1", NULL, &hints, &r_raw)); + SrsUniquePtr r(r_raw, freeaddrinfo); EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr)); } diff --git a/trunk/src/utest/srs_utest_st.cpp b/trunk/src/utest/srs_utest_st.cpp index f15ecaa96..e9475c4ea 100644 --- a/trunk/src/utest/srs_utest_st.cpp +++ b/trunk/src/utest/srs_utest_st.cpp @@ -111,7 +111,7 @@ VOID TEST(StTest, StUtimePerformance) EXPECT_LT(gettimeofday_elapsed_time > st_utime_elapsed_time ? gettimeofday_elapsed_time - st_utime_elapsed_time : - st_utime_elapsed_time - gettimeofday_elapsed_time, 10); + st_utime_elapsed_time - gettimeofday_elapsed_time, 30); } }