Upgrade flutter webrtc to 1.3.1#993
Upgrade flutter webrtc to 1.3.1#993xiaowei-guan wants to merge 6 commits intoflutter-tizen:masterfrom
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates the flutter_webrtc dependency to version 1.3.1 and introduces a TaskRunner interface to facilitate thread-safe event dispatching. New features include setVolume for audio tracks, dataChannelGetBufferedAmount, and configurable RTC logging severity. The refactor propagates the TaskRunner through various observers and managers and updates several WebRTC internal headers. Feedback identifies critical issues including a use-after-free vulnerability in setVolume, the lack of initialization for the task_runner_ member, and a dangling pointer risk with a static global logging proxy. Further improvements are requested regarding the robustness of the maybeFindDouble helper, adherence to C++ casting standards, and the restoration of a check for defined statistics members.
| RTCMediaTrack* track = MediaTrackForId(trackId); | ||
| if (nullptr == track) { | ||
| result->Error("setVolume", "setVolume() Unable to find provided track"); | ||
| return; | ||
| } | ||
|
|
||
| std::string kind = track->kind().std_string(); | ||
| if (0 != kind.compare("audio")) { | ||
| result->Error("setVolume", | ||
| "setVolume() Only audio tracks can have volume set"); | ||
| return; | ||
| } | ||
|
|
||
| auto audioTrack = static_cast<RTCAudioTrack*>(track); | ||
| audioTrack->SetVolume(volume.value()); |
There was a problem hiding this comment.
Assigning the result of MediaTrackForId (which returns a scoped_refptr) to a raw pointer RTCMediaTrack* is dangerous. The temporary scoped_refptr returned by the function will be destroyed at the end of the assignment statement, potentially decrementing the reference count to zero and deleting the track object. This leads to a use-after-free vulnerability when track is accessed later. Always store the result in a scoped_refptr to keep the object alive.
| RTCMediaTrack* track = MediaTrackForId(trackId); | |
| if (nullptr == track) { | |
| result->Error("setVolume", "setVolume() Unable to find provided track"); | |
| return; | |
| } | |
| std::string kind = track->kind().std_string(); | |
| if (0 != kind.compare("audio")) { | |
| result->Error("setVolume", | |
| "setVolume() Only audio tracks can have volume set"); | |
| return; | |
| } | |
| auto audioTrack = static_cast<RTCAudioTrack*>(track); | |
| audioTrack->SetVolume(volume.value()); | |
| scoped_refptr<RTCMediaTrack> track = MediaTrackForId(trackId); | |
| if (track == nullptr) { | |
| result->Error("setVolume", "setVolume() Unable to find provided track"); | |
| return; | |
| } | |
| std::string kind = track->kind().std_string(); | |
| if (0 != kind.compare("audio")) { | |
| result->Error("setVolume", | |
| "setVolume() Only audio tracks can have volume set"); | |
| return; | |
| } | |
| auto audioTrack = static_cast<RTCAudioTrack*>(track.get()); | |
| audioTrack->SetVolume(volume.value()); |
| std::unique_ptr<FlutterWebRTC> webrtc_; | ||
| BinaryMessenger* messenger_; | ||
| TextureRegistrar* textures_; | ||
| std::unique_ptr<TaskRunner> task_runner_; |
There was a problem hiding this comment.
The task_runner_ member is added but never initialized in the FlutterWebRtcTizenPlugin constructor. Consequently, task_runner() returns nullptr. This causes EventChannelProxyImpl::PostEvent to call sink_->Success directly on the current thread. Since WebRTC callbacks often occur on background threads and Flutter's EventSink must be used on the platform thread, this will lead to crashes. A concrete implementation of TaskRunner (e.g., using Tizen's ecore_main_loop_thread_safe_call_async) must be instantiated and assigned here.
|
|
||
| namespace flutter_webrtc_plugin { | ||
|
|
||
| static EventChannelProxy* eventChannelProxy = nullptr; |
There was a problem hiding this comment.
The static global eventChannelProxy is a raw pointer to an object owned by FlutterWebRTCBase. If the plugin is destroyed and re-initialized, or if a log message arrives after the plugin is disposed, this pointer will be dangling. This will cause a crash in the logging callback captured in initLoggerCallback. Ensure the log sink is removed and the pointer is cleared in the plugin's destructor.
| inline std::optional<double> maybeFindDouble(const EncodableMap& map, | ||
| const std::string& key) { | ||
| auto it = map.find(EncodableValue(key)); | ||
| if (it != map.end() && TypeIs<double>(it->second)) | ||
| return GetValue<double>(it->second); | ||
| return std::nullopt; | ||
| } |
There was a problem hiding this comment.
The maybeFindDouble helper only checks for the double type. However, Flutter's StandardMessageCodec may encode whole numbers as int or int32_t. To be robust and consistent with findDouble, this helper should also handle integer types.
inline std::optional<double> maybeFindDouble(const EncodableMap& map,
const std::string& key) {
auto it = map.find(EncodableValue(key));
if (it != map.end()) {
if (TypeIs<double>(it->second)) return GetValue<double>(it->second);
if (TypeIs<int>(it->second)) return static_cast<double>(GetValue<int>(it->second));
}
return std::nullopt;
}| RTCDataChannel* data_channel, std::unique_ptr<MethodResultProxy> result) { | ||
| EncodableMap params; | ||
| params[EncodableValue("bufferedAmount")] = | ||
| EncodableValue((int64_t)data_channel->buffered_amount()); |
There was a problem hiding this comment.
Avoid using C-style casts. Use static_cast instead, as per the Google C++ Style Guide followed in this repository.
| EncodableValue((int64_t)data_channel->buffered_amount()); | |
| EncodableValue(static_cast<int64_t>(data_channel->buffered_amount())); |
References
- C++ code should follow the Google C++ Style Guide, which prefers C++-style casts over C-style casts. (link)
| auto members = stats->Members(); | ||
| for (int i = 0; i < members.size(); i++) { | ||
| auto member = members[i]; | ||
| if (!member->IsDefined()) { | ||
| continue; | ||
| } | ||
| switch (member->GetType()) { |
There was a problem hiding this comment.
The check !member->IsDefined() was removed. In WebRTC, statistics members may be undefined, and attempting to access their values without checking can lead to incorrect data or undefined behavior. It is safer to keep this check.
| auto members = stats->Members(); | |
| for (int i = 0; i < members.size(); i++) { | |
| auto member = members[i]; | |
| if (!member->IsDefined()) { | |
| continue; | |
| } | |
| switch (member->GetType()) { | |
| auto members = stats->Members(); | |
| for (int i = 0; i < members.size(); i++) { | |
| auto member = members[i]; | |
| if (!member->IsDefined()) { | |
| continue; | |
| } | |
| switch (member->GetType()) { |
- Update minimum Flutter and Dart version to 3.13 and 3.1 - Fix analyze issue - Update code format - Adds compatibility with `http` 1.0 in example
No description provided.