Ошибка в экземплах ddk

Тема в разделе "WASM.NT.KERNEL", создана пользователем Nouzui, 19 фев 2007.

  1. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    я, может, просто туплю под вечер, но все же:

    \src\input\kbdclass\kbdclass.c
    Код (Text):
    1. KeyboardClassDequeueReadByFileObject(
    2.     IN PDEVICE_EXTENSION DeviceExtension,
    3.     IN PFILE_OBJECT FileObject
    4.     )
    5. /*++
    6.  
    7. Routine Description:
    8.     Dequeues the next available read with a matching FileObject
    9.    
    10. Assumptions:    
    11.     DeviceExtension->SpinLock is already held (so no further sync is required).
    12.    
    13.   --*/
    14. {
    15.     PIRP                irp = NULL;
    16.     PLIST_ENTRY         entry;
    17.     PIO_STACK_LOCATION  stack;
    18.     PDRIVER_CANCEL      oldCancelRoutine;
    19.     KIRQL oldIrql;      
    20.  
    21.     if (FileObject == NULL) {
    22.         return KeyboardClassDequeueRead (DeviceExtension);
    23.     }
    24.  
    25.     for (entry = DeviceExtension->ReadQueue.Flink;
    26.          entry != &DeviceExtension->ReadQueue;
    27.          entry = entry->Flink) {
    28.  
    29.         irp = CONTAINING_RECORD (entry, IRP, Tail.Overlay.ListEntry);
    30.         stack = IoGetCurrentIrpStackLocation (irp);
    31.         if (stack->FileObject == FileObject) {
    32.             RemoveEntryList (entry);
    33.  
    34.             oldCancelRoutine = IoSetCancelRoutine (irp, NULL);
    35.    
    36.             //
    37.             // IoCancelIrp() could have just been called on this IRP.
    38.             // What we're interested in is not whether IoCancelIrp() was called
    39.             // (ie, nextIrp->Cancel is set), but whether IoCancelIrp() called (or
    40.             // is about to call) our cancel routine. To check that, check the result
    41.             // of the test-and-set macro IoSetCancelRoutine.
    42.             //
    43.             if (oldCancelRoutine) {
    44.                 //
    45.                 //  Cancel routine not called for this IRP.  Return this IRP.
    46.                 //
    47.                 return irp;
    48.             }
    49.             else {
    50.                 //
    51.                 // This IRP was just cancelled and the cancel routine was (or will
    52.                 // be) called. The cancel routine will complete this IRP as soon as
    53.                 // we drop the spinlock. So don't do anything with the IRP.
    54.                 //
    55.                 // Also, the cancel routine will try to dequeue the IRP, so make the
    56.                 // IRP's listEntry point to itself.
    57.                 //
    58.                 ASSERT (irp->Cancel);
    59.                 InitializeListHead (&irp->Tail.Overlay.ListEntry);
    60.             }
    61.         }
    62.     }
    63.  
    64.     return NULL;
    65. }
    насколко я понимаю, зависнет, если IoSetCancelRoutine() хотя бы раз вернет NULL
     
  2. Jupiter

    Jupiter Jupiter

    Публикаций:
    0
    Регистрация:
    12 авг 2004
    Сообщения:
    532
    Адрес:
    Russia
    там же вроде else стоит?
     
  3. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    верно..
    IoSetCancelRoutine() вернет NULL
    в else выполнится InitializeListHead (&irp->Tail.Overlay.ListEntry);
    поскольку irp = CONTAINING_RECORD (entry, IRP, Tail.Overlay.ListEntry); то предыдущая операция будет эквивалентна InitializeListHead (entry)
    и что получится на следующей итерации цикла?
     
  4. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Нет. Ты упустил RemoveEntryList(entry). Она отстегнёт текущий ентри и замкнёт DeviceExtension->ReadQueue.

    При кажущейся простоте двусвязных списков иногда бывает довольно мозгодробильно ;) Советую взять бумажку и нарисовать пошагово, что происходит со списком.
     
  5. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    Four-F

    пока попробую обойтись без бумажки ))
    значит, так:
    irp = CONTAINING_RECORD (entry, IRP, Tail.Overlay.ListEntry);
    следовательно
    entry==&Tail.Overlay.ListEntry
    далее
    попался irp такой, что (stack->FileObject == FileObject)
    вошли
    RemoveEntryList (entry); удаляет Tail.Overlay.ListEntry из списка и замыкает этот список, не меняя содержимого полей Flink и Blink самого Tail.Overlay.ListEntry

    а вот теперь представим себе, что IoSetCancelRoutine (irp, NULL); возвращает NULL
    смотрим, что дальше
    ну ассерт ассертом...
    InitializeListHead (&irp->Tail.Overlay.ListEntry);
    Код (Text):
    1. VOID
    2. FORCEINLINE
    3. InitializeListHead(
    4.     IN PLIST_ENTRY ListHead
    5.     )
    6. {
    7.     ListHead->Flink = ListHead->Blink = ListHead;
    8. }
    поскольку entry==&Tail.Overlay.ListEntry, то после этого
    entry->Flink == entry->Blink == entry
    цикл повторяется
    операция entry = entry->Flink в for'е
    entry не изменится
    условие
    entry != &DeviceExtension->ReadQueue будет теперь выполняться всегда, потому что entry не меняется
    irp = CONTAINING_RECORD (entry, IRP, Tail.Overlay.ListEntry); - entry тот же, значит и irp тот же
    соответственно (stack->FileObject == FileObject)
    RemoveEntryList (entry);
    сейчас entry ссылается на самого себя
    Код (Text):
    1. VOID
    2. FORCEINLINE
    3. RemoveEntryList(
    4.     IN PLIST_ENTRY Entry
    5.     )
    6. {
    7.     PLIST_ENTRY Blink;
    8.     PLIST_ENTRY Flink;
    9.  
    10.     Flink = Entry->Flink;
    11.     Blink = Entry->Blink;
    12.     Blink->Flink = Flink;
    13.     Flink->Blink = Blink;
    14. }
    очевидно, поля entry или каких-либо элементов списка не изменятся
    IoSetCancelRoutine (irp, NULL); теперь уже гарантированно вернет NULL, поскольку вызывалась для этого же irp в прошлой итерации

    и далее все по кругу
     
  6. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Да, ты прав. После RemoveEntryList нужно обновить entry вот так.

    Код (Text):
    1. RemoveEntryList( entry );
    2. entry = entry->Blink;
    Скорее всего тот, кто писАл этот код, скопипастил этот кусок откуда-то, что-то в нём поменял и ку-ку. Хороший пример того, что имея дело с двусвязными списками надо держать ухо в остро.

    Надо глянуть в последнем ДДК - пофиксили или нет...
     
  7. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    гг

    kbdclass.sys 5.1.2600.1106 (xpsp1.020828-1920)
    Код (Text):
    1. .text:000105DE ; __stdcall KeyboardClassDequeueReadByFileObject(x,x)
    2. .text:000105DE _KeyboardClassDequeueReadByFileObject@8 proc near
    3. .text:000105DE                                         ; CODE XREF: KeyboardClassCleanupQueue(x,x,x)+28p
    4. .text:000105DE
    5. .text:000105DE pDeviceExtension= dword ptr  8
    6. .text:000105DE pFileObject     = dword ptr  0Ch
    7. .text:000105DE
    8. .text:000105DE                 push    ebx
    9. .text:000105DF                 mov     ebx, [esp+pFileObject]
    10. .text:000105E3                 test    ebx, ebx
    11. .text:000105E5                 jnz     short loc_105F2
    12. .text:000105E7                 push    [esp+pDeviceExtension]
    13. .text:000105EB                 call    _KeyboardClassDequeueRead@4 ; KeyboardClassDequeueRead(x)
    14. .text:000105F0                 jmp     short loc_10631
    15. .text:000105F2 ; ---------------------------------------------------------------------------
    16. .text:000105F2
    17. .text:000105F2 loc_105F2:                              ; CODE XREF: KeyboardClassDequeueReadByFileObject(x,x)+7j
    18. .text:000105F2                 push    esi
    19. .text:000105F3                 push    edi
    20. .text:000105F4                 mov     edi, [esp+8+pDeviceExtension]
    21. .text:000105F8                 add     edi, 70h
    22. .text:000105FB                 mov     ecx, [edi]
    23. .text:000105FD                 jmp     short loc_10629
    24. .text:000105FF ; ---------------------------------------------------------------------------
    25. .text:000105FF
    26. .text:000105FF loc_105FF:                              ; CODE XREF: KeyboardClassDequeueReadByFileObject(x,x)+4Dj
    27. .text:000105FF                 lea     eax, [ecx-58h]
    28. .text:00010602                 mov     edx, [eax+60h]
    29. .text:00010605                 cmp     [edx+18h], ebx
    30. .text:00010608                 jnz     short loc_10627
    31. .text:0001060A                 mov     edx, [ecx]
    32. .text:0001060C                 mov     esi, [ecx+4]
    33. .text:0001060F                 mov     [esi], edx
    34. .text:00010611                 mov     [edx+4], esi
    35. .text:00010614                 xor     edx, edx
    36. .text:00010616                 lea     esi, [eax+38h]
    37. .text:00010619                 xchg    edx, [esi]
    38. .text:0001061B                 test    edx, edx
    39. .text:0001061D                 jnz     short loc_1062F
    40. .text:0001061F                 add     eax, 58h
    41. .text:00010622                 mov     [eax+4], eax
    42. .text:00010625                 mov     [eax], eax
    43. .text:00010627
    44. .text:00010627 loc_10627:                              ; CODE XREF: KeyboardClassDequeueReadByFileObject(x,x)+2Aj
    45. .text:00010627                 mov     ecx, [ecx]
    46. .text:00010629
    47. .text:00010629 loc_10629:                              ; CODE XREF: KeyboardClassDequeueReadByFileObject(x,x)+1Fj
    48. .text:00010629                 cmp     ecx, edi
    49. .text:0001062B                 jnz     short loc_105FF
    50. .text:0001062D                 xor     eax, eax
    51. .text:0001062F
    52. .text:0001062F loc_1062F:                              ; CODE XREF: KeyboardClassDequeueReadByFileObject(x,x)+3Fj
    53. .text:0001062F                 pop     edi
    54. .text:00010630                 pop     esi
    55. .text:00010631
    56. .text:00010631 loc_10631:                              ; CODE XREF: KeyboardClassDequeueReadByFileObject(x,x)+12j
    57. .text:00010631                 pop     ebx
    58. .text:00010632                 retn    8
    59. .text:00010632 _KeyboardClassDequeueReadByFileObject@8 endp
     
  8. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Ну тогда проверь всё ещё раз дцать и строчи баг-репорт ;)
     
  9. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    угу.. их еще заинтересует номер лицензии тех форточек, под которыми я все это проверял итд... ))
     
  10. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Да вряд ли. Если спросят, скажешь: "Не скажу, а если будете дурацкие вопросы задавать, то багов искать больше не буду, а про этот всем раскажу на всех ваших форумах". ;)))
     
  11. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856