أصبحت العديد من الأخطاء المطبعية ورمز نسخ اللصق الموضوع الرئيسي للمقال الإضافي حول التحقق من كود هايكو بواسطة محلل PVS-Studio. ومع ذلك ، فإن هذا المقال يحكي في الغالب عن الأخطاء المتعلقة بعدم التفكير والإفلاس ، بدلاً من الأخطاء المطبعية. توضح الأخطاء التي تم العثور عليها مدى قوة العامل البشري في تطوير البرمجيات.
مقدمة
Haiku هو نظام تشغيل مجاني مفتوح المصدر لأجهزة الكمبيوتر الشخصية. يعمل فريق التطوير الدولي حاليًا على مكونات النظام. يبرز Porting Libre Office في نظام التشغيل وإصدار R1 Beta 1 الأول بين التحسينات التطويرية الهامة التي تمت مؤخرًا.
يتبع فريق من المطورين من
PVS-Studio هذا المشروع منذ عام 2015 وينشر تعليقات عن عيوب الكود. هذا هو الاستعراض الرابع في كل العصور. يمكنك قراءة المقالات السابقة عن طريق هذه الروابط:
- تحليل نظام تشغيل هايكو (عائلة BeOS) ، بواسطة PVS-Studio ، الجزء 1 ؛
- تحليل نظام تشغيل هايكو (BeOS Family) بواسطة PVS-Studio. الجزء 2
- كيف تطلق النار على قدمك في C و C ++. كتاب الطبخ هايكو OS
ميزة تحليل الرمز الأخير هي القدرة على استخدام الإصدار الرسمي من PVS-Studio لنظام التشغيل Linux. لم يتوفر PVS-Studio لنظام التشغيل Linux ، ولا تقرير مناسب لعرض الأخطاء في عام 2015. هذه المرة سنرسل التقرير الكامل في تنسيق مناسب لمطوري Haiku.
كلاسيكي
V501 هناك تعابير فرعية مماثلة إلى اليسار وإلى يمين عامل التشغيل '-': (addr_t) b - (addr_t) b BitmapManager.cpp 51
int compare_app_pointer(const ServerApp* a, const ServerApp* b) { return (addr_t)b - (addr_t)b; }
يتعين على كل مطور خلط المتغيرات
a و
b و
x و
y و
i و
j ... مرة واحدة على الأقل في حياته.
V501 هناك تعبيرات فرعية مماثلة إلى اليسار وإلى يمين "||" عامل التشغيل: الإدخال == __null || إدخال == __null MediaClient.cpp 182
status_t BMediaClient::Unbind(BMediaInput* input, BMediaOutput* output) { CALLED(); if (input == NULL || input == NULL) return B_ERROR; if (input->fOwner != this || output->fOwner != this) return B_ERROR; input->fBind = NULL; output->fBind = NULL; return B_OK; }
يتم فحص مؤشر
الإدخال نفسه في الحالة مرتين. بينما ظل مؤشر
الإخراج بدون تحديد ، مما قد يؤدي إلى dereference مؤشر فارغة.
كود ثابت:
if (input == NULL || output == NULL) return B_ERROR;
V583 يقوم
المشغل '؟:' ، بغض النظر عن تعبيره الشرطي ، دائمًا بإرجاع قيمة واحدة ونفس القيمة: 500000. usb_modeswitch.cpp 361
static status_t my_transfer_data(....) { .... do { bigtime_t timeout = directionIn ? 500000 : 500000; result = acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, timeout); .... } while (result == B_INTERRUPTED); .... }
أصبح المشغل الثلاثي عديم الجدوى ، عندما ارتكب مؤلف الكود خطأ وكتب قيمتي عائد متطابقتين -
500000 .
V519 يتم تعيين قيم "m_kindex1" لقيمتين متتاليتين. ربما هذا خطأ. خطوط التحقق: 40 ، 41. agg_trans_double_path.cpp 41
trans_double_path::trans_double_path() : m_kindex1(0.0), m_kindex2(0.0), m_base_length(0.0), m_base_height(1.0), m_status1(initial), m_status2(initial), m_preserve_x_scale(true) { } void trans_double_path::reset() { m_src_vertices1.remove_all(); m_src_vertices2.remove_all(); m_kindex1 = 0.0; m_kindex1 = 0.0; m_status1 = initial; m_status2 = initial; }
يوجد خطأ في وظيفة
إعادة الضبط : خطأ مطبعي في فهرس متغير
m_kindex2 . لن تتم إعادة تعيين هذا المتغير ، مما سيؤثر على الأرجح في تنفيذ أجزاء التعليمات البرمجية الأخرى.
V501 هناك تعبيرات فرعية متطابقة إلى اليسار وإلى يمين عامل التشغيل '>': fg [order_type :: R]> fg [order_type :: R] agg_span_image_filter_rgba.h 898
typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; void generate(color_type* span, int x, int y, unsigned len) { .... if(fg[0] < 0) fg[0] = 0; if(fg[1] < 0) fg[1] = 0; if(fg[2] < 0) fg[2] = 0; if(fg[3] < 0) fg[3] = 0; if(fg[order_type::A] > base_mask) fg[order_type::A] = base_mask; if(fg[order_type::R] > fg[order_type::R])fg[order_type::R] = fg[order_type::R]; if(fg[order_type::G] > fg[order_type::G])fg[order_type::G] = fg[order_type::G]; if(fg[order_type::B] > fg[order_type::B])fg[order_type::B] = fg[order_type::B]; .... }
في الأسطر الأخيرة ، هناك مسألتان في آن واحد: المقارنة وتعيين المتغيرات متساوية. لا أستطيع حتى أن أقترح ما كان من بنات أفكار المؤلف. سألاحظ أن هذا المقتطف مشبوه.
V570 يتم تعيين المتغير "wPipeIndex" لنفسه. CEchoGals_transport.cpp 244
ECHOSTATUS CEchoGals::CloseAudio (....) { .... wPipeIndex = wPipeIndex; m_ProcessId[ wPipeIndex ] = NULL; m_Pipes[ wPipeIndex ].wInterleave = 0; .... }
تتم تهيئة متغير
wPipeIndex من خلال قيمته الخاصة. على الأرجح ، تم إجراء خطأ مطبعي.
أخطاء مع المؤشرات
V522 قد يتم إلغاء تأشير المؤشر الخالي "currentInterface". Device.cpp 258
Device::Device(....) : .... { .... usb_interface_info* currentInterface = NULL;
يتم تهيئة مؤشر
CurrentInterface في البداية بواسطة null ثم يتم التحقق منه عند الدخول في فروع مشغل
التبديل ، ولكن ليس في جميع الحالات. يحذر المحلل من أنه عند القفز إلى تسمية حالة
USB_DESCRIPTOR_ENDPOINT_COMPANION ، قد يحدث dereference مؤشر فارغ.
V522 قد يتم إلغاء تسجيل "دليل" المؤشر الخالي. PathMonitor.cpp 1465
bool PathHandler::_EntryCreated(....) { .... Directory* directory = directoryNode->ToDirectory(); if (directory == NULL) {
أعتقد ، يوجد خطأ في شرط المقارنة لمؤشر
الدليل بقيمة فارغة. الشرط يجب أن يكون عكس ذلك. مع التطبيق الحالي ، إذا كان المتغير
dryRun خاطئ ،
فسيتم إلغاء تحديد مؤشر
الدليل الخالي.
V522 قد يتم إلغاء إدخال مؤشر "الإدخال" الخالي من المؤشر. MediaRecorder.cpp 343
void GetInput(media_input* input); const media_input& BMediaRecorder::MediaInput() const { CALLED(); media_input* input = NULL; fNode->GetInput(input); return *input; }
تتم تهيئة مؤشر
الإدخال بواسطة قيمة فارغة ويظل بمثل هذه القيمة ، حيث لا يتغير المؤشر في دالة GetInput. في الطرق الأخرى لفئة
BMediaRecorder ، يختلف التنفيذ ، على سبيل المثال:
status_t BMediaRecorder::_Connect(....) { ....
كل هذا صحيح هنا ، لكن الجزء الأول يجب إعادة كتابته ، وإلا ستُرجع الدالة مرجعًا إلى كائن محلي.
V522 قد يتم إلغاء تسجيل المؤشر الخالي "mustFree". RequestUnflattener.cpp 35
status_t Reader::Read(int32 size, void** buffer, bool* mustFree) { if (size < 0 || !buffer || mustFree)
في التعبير الشرطي حيث يتم التحقق من جميع البيانات غير الصحيحة ، قام المؤلف بكتابة خطأ مطبعي عند التحقق من مؤشر
mustFree . على الأرجح ، يجب إنهاء الوظيفة عند وجود قيمة فارغة لهذا المؤشر:
if (size < 0 || !buffer || !mustFree)
V757 من الممكن مقارنة متغير غير صحيح مع nullptr بعد تحويل النوع باستخدام 'dynamic_cast'. خطوط التحقق: 474 ، 476. recovery.cpp 474
void checkStructure(Disk &disk) { .... Inode* missing = gMissing.Get(run); dir = dynamic_cast<Directory *>(missing); if (missing == NULL) { .... } .... }
يجب على المطور التحقق من مؤشر
dir بدلاً من
فقده بعد تحويل النوع. بالمناسبة ،
غالباً ما يرتكب مطورو C # خطأ مشابه. هذا يثبت مرة أخرى أن بعض الأخطاء لا تعتمد على اللغة المستخدمة.
زوجان أكثر أماكن مماثلة في الرمز:
- V757 من الممكن مقارنة متغير غير صحيح مع nullptr بعد تحويل النوع باستخدام 'dynamic_cast'. خطوط التحقق: 355 ، 357. ExpandoMenuBar.cpp 355
- V757 من الممكن مقارنة متغير غير صحيح مع nullptr بعد تحويل النوع باستخدام 'dynamic_cast'. خطوط التحقق: 600 ، 601. ValControl.cpp 600
أخطاء الفهرس
V557 تجاوز الصفيف هو ممكن. يشير مؤشر 'BT_SCO' إلى ما وراء مجموعة الصفيف. h2upper.cpp 75
struct bt_usb_dev { .... struct list nbuffersTx[(1 + 1 + 0 + 0)];
يتكون صفيف
bdev-> nbuffersTx فقط من عنصرين ، لكن يتم معالجته بواسطة ثابت BT_SCO ، وهو 3. هنا يأتي فهرس الصفيف سوريفيري خارج الحدود.
V557 تجاوز الصفيف هو ممكن. تقوم دالة "ieee80211_send_setup" بمعالجة القيمة "16". تفقد الحجة الرابعة. خطوط التحقق: 842 ، 911. ieee80211_output.c 842
struct ieee80211_node { .... struct ieee80211_tx_ampdu ni_tx_ampdu[16];
فهرس مجموعة أخرى خارج الحدود. هذه المرة ، فقط بواسطة عنصر واحد. ساعد التحليل Interprocedural على الكشف عن الحالة عندما تمت معالجة الفهرس
ni-> ni_tx_ampdu ، والذي يتكون من 16 عنصرًا من قبل الفهرس 16. في صفيف C و C ++ يتم فهرستها من الصفر.
V781 يتم
التحقق من قيمة المتغير 'vector' بعد استخدامه. ربما هناك خطأ في منطق البرنامج. خطوط التحقق: 802 ، 805. oce_if.c 802
#define OCE_MAX_EQ 32 typedef struct oce_softc { .... OCE_INTR_INFO intrs[OCE_MAX_EQ]; .... } OCE_SOFTC, *POCE_SOFTC; static int oce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending)) { POCE_INTR_INFO ii = &sc->intrs[vector]; int rc = 0, rr; if (vector >= OCE_MAX_EQ) return (EINVAL); .... }
اكتشف المحلل أن عنصرًا من صفيف
sc-> intrs تمت معالجته بواسطة فهرس غير صالح ، والذي كان خارج الحدود. السبب هو الترتيب غير الصحيح للعمليات في الكود. أولاً ، يتم تناول العنصر ثم يأتي التحقق مما إذا كانت قيمة الفهرس صالحة.
قد يقول البعض أنه لن يكون هناك أي مشكلة. لا يزيل قيمة عنصر الصفيف ، بل يأخذ فقط عنوان الخلية. لكن لا ، هذه ليست الطريقة للقيام بالأشياء. اقرأ المزيد: "
إلغاء مؤشر غير صحيح يؤدي سلوك غير محدد ".
V519 يتم تخصيص القيم مرتين على التوالي. ربما هذا خطأ. خطوط التحقق: 199 ، 200. nvme_ctrlr.c 200
static void nvme_ctrlr_set_intel_supported_features(struct nvme_ctrlr *ctrlr) { bool *supported_feature = ctrlr->feature_supported; supported_feature[NVME_INTEL_FEAT_MAX_LBA] = true; supported_feature[NVME_INTEL_FEAT_MAX_LBA] = true; supported_feature[NVME_INTEL_FEAT_NATIVE_MAX_LBA] = true; supported_feature[NVME_INTEL_FEAT_POWER_GOVERNOR_SETTING] = true; supported_feature[NVME_INTEL_FEAT_SMBUS_ADDRESS] = true; supported_feature[NVME_INTEL_FEAT_LED_PATTERN] = true; supported_feature[NVME_INTEL_FEAT_RESET_TIMED_WORKLOAD_COUNTERS] = true; supported_feature[NVME_INTEL_FEAT_LATENCY_TRACKING] = true; }
يتم تعيين نفس القيمة لعنصر الصفيف مع فهرس
NVME_INTEL_FEAT_MAX_LBA . والخبر السار هو أن هذه الوظيفة تقدم جميع الثوابت الممكنة مما يجعل هذا الكود مجرد نتيجة لبرمجة Copy-Paste. ولكن هناك احتمالات سوف تتسلل الأخطاء إلى هنا.
V519 يتم تعيين متغير "copiedPath [len]" قيم مرتين على التوالي. ربما هذا خطأ. خطوط التحقق: 92 ، 93. kernel_emu.cpp 93
int UserlandFS::KernelEmu::new_path(const char *path, char **copy) { ....
حسنًا ، حظ المبرمج هنا سيئ الحظ في النسخ. تتم إضافة الرمز "dot" إلى سطر ويتم إعادة كتابته باستخدام محطة فارغة. من المحتمل جدًا أن يكون المؤلف قد نسخ الخط ونسى زيادة الفهرس.
ظروف غريبة
V517 استخدام
نمط "if (A) {...} آخر إذا تم اكتشاف (A) {...}". هناك احتمال لوجود خطأ منطقي. خطوط التحقق: 1407 ، 1410. FindPanel.cpp 1407
void FindPanel::BuildAttrQuery(BQuery* query, bool &dynamicDate) const { .... case B_BOOL_TYPE: { uint32 value; if (strcasecmp(textControl->Text(), "true") == 0) { value = 1; } else if (strcasecmp(textControl->Text(), "true") == 0) { value = 1; } else value = (uint32)atoi(textControl->Text()); value %= 2; query->PushUInt32(value); break; } .... }
نسخ الكود أدى إلى خطأين في وقت واحد. التعبيرات الشرطية متطابقة. على الأرجح ، يجب أن تكون المقارنة مع السلسلة "false" بدلاً من "true" في أحدها. كذلك في الفرع الذي يعالج القيمة "false" ،
القيمة التي يجب تغييرها من
1 إلى
0 . تتطلب الخوارزمية تحويل أي قيم أخرى ، تختلف عن
صواب أو
خطأ ، في رقم باستخدام وظيفة
atoi . ولكن بسبب وجود خطأ ، سيتم إدخال النص "false" في الوظيفة.
تعبير
V547 'error == ((int) 0)' صحيح دائمًا. Directory.cpp 688
int32 BDirectory::CountEntries() { status_t error = Rewind(); if (error != B_OK) return error; int32 count = 0; BPrivate::Storage::LongDirEntry entry; while (error == B_OK) { if (GetNextDirents(&entry, sizeof(entry), 1) != 1) break; if (strcmp(entry.d_name, ".") != 0 && strcmp(entry.d_name, "..") != 0) count++; } Rewind(); return (error == B_OK ? count : error); }
اكتشف المحلل أن قيمة متغير
الخطأ ستكون دائمًا
B_OK . بكل تأكيد ، تم تفويت هذا التعديل المتغير في حلقة التكرار.
V564 يتم تطبيق عامل التشغيل "&" على قيمة نوع منطقي. ربما نسيت تضمين الأقواس أو المقصود استخدام عامل التشغيل "&&". strtod.c 545
static int lo0bits(ULong *y) { int k; ULong x = *y; .... if (!(x & 1)) { k++; x >>= 1; if (!x & 1)
على الأرجح أنه في التعبير الشرطي الأخير ، نسى الشخص وضع الأقواس ، كما في الشروط أعلاه. من المرجح أن يكون المشغل التكميلي خارج الأقواس:
if (!(x & 1))
V590 النظر في فحص هذا التعبير. التعبير مفرط أو يحتوي على خطأ مطبعي. PoseView.cpp 5851
bool BPoseView::AttributeChanged(const BMessage* message) { .... result = poseModel->OpenNode(); if (result == B_OK || result != B_BUSY) break; .... }
هذا غير واضح ، لكن نتيجة الشرط لا تعتمد على قيمة قيمة B_OK. لذلك يمكن تبسيطها:
If (result != B_BUSY) break;
يمكنك التحقق بسهولة من خلال رسم جدول الحقيقة لقيم متغير
النتيجة . إذا أراد أحدهم مراعاة القيم الأخرى على وجه التحديد ، يختلف عن
B_OK و
B_BUSY ، فيجب إعادة كتابة الرمز بطريقة أخرى.
شظايا أكثر مماثلة:
- V590 النظر في فحص هذا التعبير. التعبير مفرط أو يحتوي على خطأ مطبعي. Tracker.cpp 1714
- V590 النظر في فحص هذا التعبير. التعبير مفرط أو يحتوي على خطأ مطبعي. if_ipw.c 1871
V590 خذ بعين الاعتبار فحص 'argc == 0 || argc! = 2 'تعبير. التعبير مفرط أو يحتوي على خطأ مطبعي. cmds.c 2667
void unsetoption(int argc, char *argv[]) { .... if (argc == 0 || argc != 2) { fprintf(ttyout, "usage: %s option\n", argv[0]); return; } .... }
ربما هذا هو أبسط مثال يوضح عمل تشخيص
V590 . تحتاج إلى عرض وصف البرنامج في حالة عدم وجود وسيطات مرت ، أو عدم وجود اثنتين منها. من الواضح أن أي قيم بخلاف القيمتين ، بما في ذلك الصفر ، لن تفي بالشرط. لذلك ، يمكن تبسيط الحالة بأمان لهذا:
if (argc != 2) { fprintf(ttyout, "usage: %s option\n", argv[0]); return; }
V590 خذ بعين الاعتبار فحص '* ptr =='؛ ' && * ptr! = '\ 0' 'التعبير. التعبير مفرط أو يحتوي على خطأ مطبعي. pc.c 316
ULONG parse_expression(char *str) { .... ptr = skipwhite(ptr); while (*ptr == SEMI_COLON && *ptr != '\0') { ptr++; if (*ptr == '\0') continue; val = assignment_expr(&ptr); } .... }
في هذا المثال ، تم تغيير عامل التشغيل المنطقي ، لكن المنطق لا يزال هو نفسه. هنا تعتمد حالة حلقة
الإيقاف فقط على ما إذا كانت الشخصية تساوي
SEMI_COLON أم لا.
V590 النظر في فحص هذا التعبير. التعبير مفرط أو يحتوي على خطأ مطبعي. writembr.cpp 99
int main(int argc, char** argv) { .... string choice; getline(cin, choice, '\n'); if (choice == "no" || choice == "" || choice != "yes") { cerr << "MBR was NOT written" << endl; fs.close(); return B_ERROR; } .... }
هناك بالفعل ثلاثة شروط في هذا المثال. يمكن أيضًا تبسيطه قبل التحقق مما إذا كان المستخدم قد اختار "نعم" أم لا:
if (choice != "yes") { cerr << "MBR was NOT written" << endl; fs.close(); return B_ERROR; }
متنوع
V530 يجب استخدام قيمة الإرجاع للدالة "start". IMAPFolder.cpp 414
void IMAPFolder::RegisterPendingBodies(...., const BMessenger* replyTo) { .... IMAP::MessageUIDList::const_iterator iterator = uids.begin(); for (; iterator != uids.end(); iterator++) { if (replyTo != NULL) fPendingBodies[*iterator].push_back(*replyTo); else fPendingBodies[*iterator].begin();
العثور على محلل استدعاء عديمة الفائدة من التكرار
تبدأ (). لا أستطيع تخيل كيفية إصلاح الكود. يجب على المطورين الانتباه إلى هذا الرمز.
V609 قسّم على صفر. نطاق المقام [0..64]. UiUtils.cpp 544
static int32 GetSIMDFormatByteSize(uint32 format) { switch (format) { case SIMD_RENDER_FORMAT_INT8: return sizeof(char); case SIMD_RENDER_FORMAT_INT16: return sizeof(int16); case SIMD_RENDER_FORMAT_INT32: return sizeof(int32); case SIMD_RENDER_FORMAT_INT64: return sizeof(int64); case SIMD_RENDER_FORMAT_FLOAT: return sizeof(float); case SIMD_RENDER_FORMAT_DOUBLE: return sizeof(double); } return 0; } const BString& UiUtils::FormatSIMDValue(const BVariant& value, uint32 bitSize, uint32 format, BString& _output) { _output.SetTo("{"); char* data = (char*)value.ToPointer(); uint32 count = bitSize / (GetSIMDFormatByteSize(format) * 8);
ترجع الدالة
GetSIMDFormatByteSize حقًا
0 كقيمة افتراضية ، مما قد يؤدي إلى القسمة على صفر.
V654 الشرط 'specificSequence! = Sequence' of loop is false دائماً. pthread_key.cpp 55
static void* get_key_value(pthread_thread* thread, uint32 key, int32 sequence) { pthread_key_data& keyData = thread->specific[key]; int32 specificSequence; void* value; do { specificSequence = keyData.sequence; if (specificSequence != sequence) return NULL; value = keyData.value; } while (specificSequence != sequence); keyData.value = NULL; return value; }
المحلل هو الصحيح أن حالة
حين المشغل هو دائما خاطئ. لهذا السبب ، لا تعمل الحلقة أكثر من تكرار واحد. بمعنى آخر ، لن يتغير شيء إذا كتبت
(0) . كل هذا غريب ويحتوي هذا الكود على خطأ منطقي. يجب على المطورين النظر بعناية في هذا المقتطف.
V672 ربما لا توجد حاجة لإنشاء متغير "المسار" الجديد هنا. إحدى وسيطات الوظيفة لها نفس الاسم وهذه الوسيطة هي مرجع. خطوط التحقق: 348 ، 429. translate.cpp 429
status_t Translator::FindPath(...., TypeList &path, double &pathQuality) { .... TypeList path; double quality; if (FindPath(&formats[j], stream, typesSeen, path, quality) == B_OK) { if (bestQuality < quality * formatQuality) { bestQuality = quality * formatQuality; bestPath.SetTo(path); bestPath.Add(formats[j].type); status = B_OK; } } .... }
يتم تمرير متغير
المسار إلى وظيفة
FindPath حسب المرجع. مما يعني أنه يمكن تعديل هذا المتغير في نص الوظيفة. ولكن هناك متغير محلي بنفس الاسم ، والذي تم تعديله. في هذه الحالة ، ستبقى جميع التغييرات فقط في المتغير المحلي. قد يرغب مؤلف التعليمات البرمجية في إعادة تسمية المتغير المحلي أو إزالته.
V705 من الممكن أن تكون كتلة "آخر" قد تم نسيانها أو التعليق عليها ، مما أدى إلى تغيير منطق عمليات البرنامج. HostnameView.cpp 109
status_t HostnameView::_LoadHostname() { BString fHostnameString; char hostname[MAXHOSTNAMELEN]; if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { fHostnameString.SetTo(hostname, MAXHOSTNAMELEN); fHostname->SetText(fHostnameString); return B_OK; } else return B_ERROR; }
مثال تنسيق التعليمات البرمجية رديئة. لا تغير الكلمة الرئيسية "المعلقة"
الأخرى المنطق بعد ، ولكن بمجرد إدراج جزء من الشفرة قبل عامل
الإرجاع ، لن يكون المنطق هو نفسه.
تتم إعادة كتابة "قائمة" المعلمة
V763 دائمًا في
هيكل الوظيفة قبل استخدامها. video.cpp 648
bool video_mode_hook(Menu *menu, MenuItem *item) { video_mode *mode = NULL; menu = item->Submenu(); item = menu->FindMarked(); .... }
لقد وجدت العديد من الحالات عندما يتم إعادة كتابة وسيطات الدالة عند إدخال الوظيفة. هذا السلوك يضلل المطورين الآخرين الذين يطلقون على هذه الوظائف ذاتها.
القائمة الكاملة للأماكن المشبوهة:
- تتم إعادة كتابة المعلمة V763 'force_16bit' دائمًا في نصوص الوظيفة قبل استخدامها. ata_adapter.cpp 151
- تتم إعادة كتابة المعلمة V763 'force_16bit' دائمًا في نصوص الوظيفة قبل استخدامها. ata_adapter.cpp 179
- تتم إعادة كتابة "قائمة" المعلمة V763 دائمًا في هيكل الوظيفة قبل استخدامها. video.cpp 264
- V763 يتم دائمًا إعادة كتابة المعلمة "الطول" في جسم الوظيفة قبل استخدامها. MailMessage.cpp 677
- تتم إعادة كتابة "إدخال" المعلمة V763 دائمًا في نصوص الوظيفة قبل استخدامها. IconCache.cpp 773
- تتم إعادة كتابة "إدخال" المعلمة V763 دائمًا في نصوص الوظيفة قبل استخدامها. IconCache.cpp 832
- تتم إعادة كتابة "إدخال" المعلمة V763 دائمًا في نصوص الوظيفة قبل استخدامها. IconCache.cpp 864
- تتم إعادة كتابة المعلمة V763 'rect' دائمًا في هيكل الوظيفة قبل استخدامها. ErrorLogWindow.cpp 56
- تتم إعادة كتابة المعلمة V763 "updateRect" دائمًا في هيكل الوظيفة قبل استخدامها. CalendarMenuWindow.cpp 49
- تتم إعادة كتابة المعلمة V763 'rect' دائمًا في هيكل الوظيفة قبل استخدامها. MemoryView.cpp 165
- تتم إعادة كتابة المعلمة V763 'rect' دائمًا في هيكل الوظيفة قبل استخدامها. TypeEditors.cpp 1124
- V763 يتم دائمًا إعادة كتابة المعلمة "الارتفاع" في جسم الوظيفة قبل استخدامها. Workspaces.cpp 857
- V763 يتم دائمًا إعادة كتابة المعلمة "عرض" في نصوص الوظيفة قبل استخدامها. Workspaces.cpp 856
- تتم إعادة كتابة "الإطار" للمعلمة V763 دائمًا في هيكل الوظيفة قبل استخدامه. SwatchGroup.cpp 48
- تتم إعادة كتابة "الإطار" للمعلمة V763 دائمًا في هيكل الوظيفة قبل استخدامه. PlaylistWindow.cpp 89
- تتم إعادة كتابة المعلمة V763 'rect' دائمًا في هيكل الوظيفة قبل استخدامها. ConfigView.cpp 78
- تتم إعادة كتابة المعلمة V763 دائمًا في جسم الوظيفة قبل استخدامها. mkntfs.c 3917
- تتم إعادة كتابة المعلمة V763 "rxchainmask" دائمًا في هيكل الوظيفة قبل استخدامها. ar5416_cal.c 463
- تتم إعادة كتابة المعلمة V763 دائمًا في جسم الوظيفة قبل استخدامها. if_iwn.c 6854
استنتاج
مشروع هايكو هو مصدر لأخطاء شيقة ونادرة. لقد أضفنا إلى قاعدة البيانات الخاصة بنا بعض أمثلة الأخطاء وقمنا بإصلاح بعض المشكلات المتعلقة بالمحلل التي ظهرت عند تحليل الرمز.
إذا لم تقم بفحص شفرتك باستخدام بعض أدوات تحليل الشفرة لفترة طويلة ، فمن المحتمل أن بعض المشكلات التي وصفتها مختبئة في شفرتك. استخدم PVS-Studio في مشروعك (إذا كان مكتوبًا بـ C أو C ++ أو C # أو Java) للتحكم في جودة الرمز. قم بتنزيل المحلل
هنا دون تسجيل أو الرسائل القصيرة.
هل تريد أن تجرب هايكو ولديك أسئلة؟ يدعوك مطورو Haiku إلى
قناة التلغراف .