bluetech / pcsc-rust

Rust bindings to PC/SC for smart card communication
https://docs.rs/pcsc
MIT License
111 stars 23 forks source link

Panics at protocol number #4

Closed RokLenarcic closed 7 years ago

RokLenarcic commented 7 years ago

I'm not sure about this bug but I tried to run some of your examples and I've got the following error when reading the protocol of the card reader:

OS: macOS

Readers: ["Gemalto PC Twin Reader"]
thread 'main' panicked at 'impossible protocol: 0x7fff00000001', /Users/.../pcsc-0.1.0/src/lib.rs:168
stack backtrace:
   0:        0x10ba2b393 - std::sys::imp::backtrace::tracing::imp::unwind_backtrace::hcc709dd93d82a051
   1:        0x10ba2c726 - std::panicking::default_hook::{{closure}}::he392668e67778d9e
   2:        0x10ba2c33b - std::panicking::default_hook::h2ade4aa81d4f8204
   3:        0x10ba2ebd7 - std::panicking::rust_panic_with_hook::h4573918fc9f80a34
   4:        0x10ba2eac4 - std::panicking::begin_panic::hea1fbdbb50f104e1
   5:        0x10ba2e9e2 - std::panicking::begin_panic_fmt::hc84782a62933404a
   6:        0x10ba22e7e - pcsc::Protocol::from_raw::hc85c8e11e656f223
   7:        0x10ba23713 - pcsc::Context::connect::hcf4a60413cc60c0c
   8:        0x10ba20019 - card_reader::main::hadbeacae176a8d6e
   9:        0x10ba2f6da - __rust_maybe_catch_panic
  10:        0x10ba2ee96 - std::rt::lang_start::ha1f4f04346e51ef5
  11:        0x10ba20cd9 - main

Could it be possible that you are grabbing too many bits when determining protocols? That 0x7fff start seems awfully suspicious.

bluetech commented 7 years ago

Great, someone with macOS! As the README states, I have only had a chance to compile-test on macOS.

Which value did you pass for the preferred_protocols parameter to Card::connect? (The examples use PROTOCOL_ANY).

Do you happen to know which protocol your card reader is using? If it's a USB card reader, it's probably T0, whose value is 0x0001 - which is what you get if you remove the 0x7fff part.

Maybe I have an incorrect integer type somewhere, or maybe macOS has some different behavior, or a bug. But I'll wait for you answers first.

bluetech commented 7 years ago

Sorry, Card::connect -> Context::connect.

RokLenarcic commented 7 years ago

I ran the connect example. I checked out your repository and did the following:

pub type DWORD = u32;
pub type LONG = i32;
pub type ULONG = u32;

Boom!

Readers: ["Gemalto PC Twin Reader"]
Status: STATUS_PRESENT | STATUS_POWERED | STATUS_SPECIFIC
Protocol: T0
RAPDU: [106, 130]
ATR: [59, 59, 148, 0, 0, 100, 14, 62, 2, 240, 49, 128, 14, 144, 0]
Vendor IFD version: [0, 0, 0, 2]
Vendor name: Gemalto

Works. Looks like macOS, despite being 64-bit operating system, uses a 32-bit library here?

bluetech commented 7 years ago

Yes, it's most likely that these are defined differently for macOS. Looking at pcsclite's code, it looks like the types you wrote are correct: https://github.com/LudovicRousseau/PCSC/blob/88a53f3ed21aa645e7c65661162f832a053fb9de/src/PCSC/wintypes.h#L46

But I know that macOS no longer uses pcsclite, but a custom implementation. So it would be nice if you could maybe look at the headers and see how they typedef DWORD & friends these days. I'm not sure where C header files are located in macOS, but if you find it, look at the files PCSC/wintypes.h, PCSC/winscard.h.

BTW, it would be great if you can check whether the monitor example program works; this has traditionally been the buggiest on macOS.

Thanks!

RokLenarcic commented 7 years ago

Monitor example just prints "Adding "Gemalto PC Twin Reader" and exits instantly.

RokLenarcic commented 7 years ago
/*
 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 *
 * This Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * @APPLE_LICENSE_HEADER_END@
 */

/*
 * MUSCLE SmartCard Development ( http://www.linuxnet.com )
 *
 * Copyright (C) 1999-2003
 *  David Corcoran <corcoran@linuxnet.com>
 *  Ludovic Rousseau <ludovic.rousseau@free.fr>
 *
 * $Id: winscard.h 123 2010-03-27 10:50:42Z ludovic.rousseau@gmail.com $
 */

/**
 * @file
 * @brief This handles smartcard reader communications.
 */

#ifndef __winscard_h__
#define __winscard_h__

#include <PCSC/pcsclite.h>
#include <stdint.h>
//#include "pcscexport.h"

#ifdef __cplusplus
extern "C"
{
#endif

#ifndef PCSC_API
#define PCSC_API
#endif

    PCSC_API int32_t SCardEstablishContext(uint32_t dwScope,
                                           const void *pvReserved1, const void *pvReserved2, LPSCARDCONTEXT phContext);

    PCSC_API int32_t SCardReleaseContext(SCARDCONTEXT hContext);

    PCSC_API int32_t SCardIsValidContext(SCARDCONTEXT hContext);

    PCSC_API int32_t SCardSetTimeout(SCARDCONTEXT hContext, uint32_t dwTimeout);

    PCSC_API int32_t SCardConnect(SCARDCONTEXT hContext,
                                  const char *szReader,
                                  uint32_t dwShareMode,
                                  uint32_t dwPreferredProtocols,
                                  LPSCARDHANDLE phCard, uint32_t *pdwActiveProtocol);

    PCSC_API int32_t SCardReconnect(SCARDHANDLE hCard,
                                    uint32_t dwShareMode,
                                    uint32_t dwPreferredProtocols,
                                    uint32_t dwInitialization, uint32_t *pdwActiveProtocol);

    PCSC_API int32_t SCardDisconnect(SCARDHANDLE hCard, uint32_t dwDisposition);

    PCSC_API int32_t SCardBeginTransaction(SCARDHANDLE hCard);

    PCSC_API int32_t SCardEndTransaction(SCARDHANDLE hCard, uint32_t dwDisposition);

    PCSC_API int32_t SCardCancelTransaction(SCARDHANDLE hCard);

    PCSC_API int32_t SCardStatus(SCARDHANDLE hCard,
                                 char *mszReaderNames, uint32_t *pcchReaderLen,
                                 uint32_t *pdwState,
                                 uint32_t *pdwProtocol,
                                 unsigned char *pbAtr, uint32_t *pcbAtrLen);

    PCSC_API int32_t SCardGetStatusChange(SCARDCONTEXT hContext,
                                          uint32_t dwTimeout,
                                          LPSCARD_READERSTATE_A rgReaderStates, uint32_t cReaders);

    PCSC_API int32_t SCardControl(SCARDHANDLE hCard,
                                  const void *pbSendBuffer, uint32_t cbSendLength,
                                  void *pbRecvBuffer, uint32_t *pcbRecvLength);

    PCSC_API int32_t SCardControl132(SCARDHANDLE hCard, uint32_t dwControlCode,
                                     const void *pbSendBuffer, uint32_t cbSendLength,
                                     void *pbRecvBuffer, uint32_t cbRecvLength, uint32_t *lpBytesReturned);

    PCSC_API int32_t SCardTransmit(SCARDHANDLE hCard,
                                   LPCSCARD_IO_REQUEST pioSendPci,
                                   const unsigned char *pbSendBuffer, uint32_t cbSendLength,
                                   LPSCARD_IO_REQUEST pioRecvPci,
                                   unsigned char *pbRecvBuffer, uint32_t *pcbRecvLength);

    PCSC_API int32_t SCardListReaderGroups(SCARDCONTEXT hContext,
                                           char *mszGroups, uint32_t *pcchGroups);

    PCSC_API int32_t SCardListReaders(SCARDCONTEXT hContext,
                                      const char *mszGroups,
                                      char *mszReaders, uint32_t *pcchReaders);

    PCSC_API int32_t SCardCancel(SCARDCONTEXT hContext);

    PCSC_API int32_t SCardGetAttrib(SCARDHANDLE hCard, uint32_t dwAttrId,
                                    uint8_t *pbAttr, uint32_t *pcbAttrLen);

    PCSC_API int32_t SCardSetAttrib(SCARDHANDLE hCard, uint32_t dwAttrId,
                                    const uint8_t *pbAttr, uint32_t cbAttrLen);

    void SCardUnload(void);

#ifdef __cplusplus
}
#endif

/*
 To support the newer version of SCardControl, we define it
 as follows. The old version number was 1.1.2, the new call
 appears in 1.3.2 of pcsc-lite (or perhaps earlier).
 */

#if !defined(USE_SCARD_CONTROL_112)
#define SCardControl SCardControl132
#endif /* USE_SCARD_CONTROL_112 */

#endif
RokLenarcic commented 7 years ago
/*
 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 *
 * This Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * @APPLE_LICENSE_HEADER_END@
 */

/*
 * MUSCLE SmartCard Development ( http://www.linuxnet.com )
 *
 * Copyright (C) 1999
 *  David Corcoran <corcoran@linuxnet.com>
 *
 * $Id: wintypes.h 123 2010-03-27 10:50:42Z ludovic.rousseau@gmail.com $
 */

/**
 * @file
 * @brief This keeps a list of Windows(R) types.
 */

#ifndef __wintypes_h__
#define __wintypes_h__

#ifdef __cplusplus
extern "C"
{
#endif

#if !defined(WIN32)

#include <stdint.h>

#ifndef BYTE
    typedef uint8_t BYTE;
#endif
    typedef uint8_t UCHAR;
    typedef uint8_t *PUCHAR;
    typedef uint16_t USHORT;

#ifndef __COREFOUNDATION_CFPLUGINCOM__
    typedef uint32_t ULONG;
    typedef void *LPVOID;
    typedef int16_t BOOL;
#endif

    typedef uint32_t *PULONG;
    typedef const void *LPCVOID;
    typedef uint32_t DWORD;
    typedef uint32_t *PDWORD;
    typedef uint16_t WORD;
    typedef int32_t LONG;
    typedef int32_t RESPONSECODE;
    typedef const char *LPCSTR;
    typedef const BYTE *LPCBYTE;
    typedef BYTE *LPBYTE;
    typedef DWORD *LPDWORD;
    typedef char *LPSTR;

    /* these types are deprecated but still used by old drivers and applications
     * You should use LPSTR instead */
    typedef char *LPTSTR ;
    typedef const char *LPCTSTR ;
    typedef char *LPCWSTR
#ifdef __GNUC__
    /* __attribute__ is a GCC only extension */
    __attribute__ ((deprecated))
#endif
    ;

#else
#include <windows.h>
#endif

#ifdef __cplusplus
}
#endif

#endif
RokLenarcic commented 7 years ago

Monitor example crashes on

            try_pcsc!(ffi::SCardGetStatusChange(
                self.handle,
                timeout_ms,
                readers.as_mut_ptr() as *mut ffi::SCARD_READERSTATE,
                readers.len() as DWORD,
            ));

But there's no error.

bluetech commented 7 years ago

I pushed a fix for the types in pcsc-sys. I'll do a release soon.

I guessed that monitor wouldn't work, because of https://ludovicrousseau.blogspot.co.il/2015/12/os-x-el-capitan-missing-feature.html. But it definitely should return some error/panic, and not crash silently. Can you run the program under gdb (or maybe it's lldb now), and see if you can get a backtrace? That would be something like that:

$ git pull  # Pull the latest fix
$ cargo test --all
$ gdb ./target/debug/examples/monitor
(gdb) r
<here it should crash>
(gdb) bt full

and paste the output.

RokLenarcic commented 7 years ago

First think I noticed is that it complains about c_long being unused import. The second thing is that it doesn't complain about c_ulong being unused. There are two of those still in there. I am not sure if that is ok or not. I also noticed that the cancel example exits normally after 5 seconds instead of exiting with a timeout.

LLDB:

(lldb) target create "./target/debug/examples/monitor"
Current executable set to './target/debug/examples/monitor' (x86_64).
(lldb) r
Process 30110 launched: './target/debug/examples/monitor' (x86_64)
Adding "Gemalto PC Twin Reader"
Process 30110 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
    frame #0: 0x00007fff97ebdb52 libsystem_c.dylib`strlen + 18
libsystem_c.dylib`strlen:
->  0x7fff97ebdb52 <+18>: pcmpeqb (%rdi), %xmm0
    0x7fff97ebdb56 <+22>: pmovmskb %xmm0, %esi
    0x7fff97ebdb5a <+26>: andq   $0xf, %rcx
    0x7fff97ebdb5e <+30>: orq    $-0x1, %rax
bluetech commented 7 years ago

I am not sure if that is ok or not.

It's probably not OK! Just to make sure that these should be u32, can you paste the definition of the SCARD_IO_REQUEST struct? It should be in one of the headers under PCSC/.

I will fix the unused import warnings after that.

EXC_BAD_ACCESS

Hmm, that's strange. What I'm thinking is that the definition of SCARD_READERSTATE in pcsc-sys is incorrect for macOS. So, can you paste the definition of this struct as well? And also the definition of MAX_ATR_SIZE (if there is one), which is the size of the rgbAtr array in that struct.

Thanks again :)

RokLenarcic commented 7 years ago
    typedef struct
    {
        const char *szReader;
        void *pvUserData;
        uint32_t dwCurrentState;
        uint32_t dwEventState;
        uint32_t cbAtr;
        unsigned char rgbAtr[MAX_ATR_SIZE];
    }
    SCARD_READERSTATE_A;

    typedef SCARD_READERSTATE_A SCARD_READERSTATE, *PSCARD_READERSTATE_A,
    *LPSCARD_READERSTATE_A;

    /** Protocol Control Information (PCI) */
    typedef struct _SCARD_IO_REQUEST
    {
        uint32_t dwProtocol;    /**< Protocol identifier */
        uint32_t cbPciLength;   /**< Protocol Control Inf Length */
    }
    SCARD_IO_REQUEST, *PSCARD_IO_REQUEST, *LPSCARD_IO_REQUEST;

    typedef const SCARD_IO_REQUEST *LPCSCARD_IO_REQUEST;

    extern SCARD_IO_REQUEST g_rgSCardT0Pci, g_rgSCardT1Pci,
    g_rgSCardRawPci;

#define MAX_ATR_SIZE 33 /**< Maximum ATR size */

bluetech commented 7 years ago

I've pushed fixes for the unused imports and the definition of SCARD_IO_REQUEST.

The definition of SCARD_READERSTATE is correct, however, so that's not the cause.

Maybe the fix to SCARD_IO_REQUEST also fixes the monitor crash? Do you mind trying that one again? If it still doesn't work, please show the output of bt full in the lldb prompt.

RokLenarcic commented 7 years ago

Well now I get:

Adding "Gemalto PC Twin Reader"
Segmentation fault: 11

And here's the debug (I used bt all, bt full doesn't seem to be a valid command).

(lldb) r
Process 30944 launched: './target/debug/examples/monitor' (x86_64)
Adding "Gemalto PC Twin Reader"
Process 30944 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
    frame #0: 0x00007fff97ebdb52 libsystem_c.dylib`strlen + 18
libsystem_c.dylib`strlen:
->  0x7fff97ebdb52 <+18>: pcmpeqb (%rdi), %xmm0
    0x7fff97ebdb56 <+22>: pmovmskb %xmm0, %esi
    0x7fff97ebdb5a <+26>: andq   $0xf, %rcx
    0x7fff97ebdb5e <+30>: orq    $-0x1, %rax
(lldb) bt all
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
  * frame #0: 0x00007fff97ebdb52 libsystem_c.dylib`strlen + 18
    frame #1: 0x00007fff97f1892b libsystem_c.dylib`strdup + 18
    frame #2: 0x00007fff980d1b40 libxpc.dylib`xpc_string_create + 11
    frame #3: 0x00007fff980d1b12 libxpc.dylib`xpc_dictionary_set_string + 24
    frame #4: 0x00007fff876ecd3f PCSC`__SCardGetStatusChange_block_invoke + 86
    frame #5: 0x00007fff876ec854 PCSC`transact + 484
    frame #6: 0x00007fff876ecc71 PCSC`SCardGetStatusChange + 428
    frame #7: 0x0000000100004245 monitor`pcsc::{{impl}}::get_status_change<core::option::Option<std::time::duration::Duration>>(self=0x00007fff5fbfeb48, timeout=Option<std::time::duration::Duration> @ 0x00007fff5fbfe978, readers=&mut [pcsc::ReaderState] @ 0x00007fff5fbfe990) at lib.rs:804
    frame #8: 0x0000000100005b6b monitor`monitor::main at monitor.rs:42
    frame #9: 0x00000001000146fb monitor`panic_unwind::__rust_maybe_catch_panic at lib.rs:98 [opt]
    frame #10: 0x0000000100013dd7 monitor`std::rt::lang_start [inlined] std::panicking::try<(),fn()> at panicking.rs:433 [opt]
    frame #11: 0x0000000100013da8 monitor`std::rt::lang_start [inlined] std::panic::catch_unwind<fn(),()> at panic.rs:361 [opt]
    frame #12: 0x0000000100013da8 monitor`std::rt::lang_start at rt.rs:57 [opt]
    frame #13: 0x0000000100005f7a monitor`main + 42
    frame #14: 0x00007fff97e87235 libdyld.dylib`start + 1

  thread #2
    frame #0: 0x00007fff97fb644e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x00007fff980a0695 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x00007fff980a00f1 libsystem_pthread.dylib`start_wqthread + 13

  thread #3
    frame #0: 0x00007fff97fb644e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x00007fff980a0502 libsystem_pthread.dylib`_pthread_wqthread + 1023
    frame #2: 0x00007fff980a00f1 libsystem_pthread.dylib`start_wqthread + 13

Could it be a problem with pointer (reference) width? Or the wrong ABI (extern "system" vs extern "C")?

bluetech commented 7 years ago

I think the problem might be that SCARD_IO_REQUEST and SCARD_READERSTATE should be packed on macOS. I had missed that on reading the pcsclite.h header on my machine.

Would you please try applying this patch, and see if it fixes the problem?

diff --git a/pcsc-sys/src/lib.rs b/pcsc-sys/src/lib.rs
index 686cab4..429ca41 100644
--- a/pcsc-sys/src/lib.rs
+++ b/pcsc-sys/src/lib.rs
@@ -146,7 +146,8 @@ pub const MAX_ATR_SIZE: usize = 33;
 pub const MAX_BUFFER_SIZE: usize = 264;
 pub const MAX_BUFFER_SIZE_EXTENDED: usize = 4 + 3 + (1 << 16) + 3 + 2;

-#[repr(C)]
+#[cfg_attr(not(target_os = "macos"), repr(C))]
+#[cfg_attr(target_os = "macos", repr(C, packed))]
 pub struct SCARD_IO_REQUEST {
     pub dwProtocol: DWORD,
     pub cbPciLength: DWORD,
@@ -157,7 +158,8 @@ pub const ATR_BUFFER_SIZE: usize = MAX_ATR_SIZE;
 #[cfg(windows)]
 pub const ATR_BUFFER_SIZE: usize = 36;

-#[repr(C)]
+#[cfg_attr(not(target_os = "macos"), repr(C))]
+#[cfg_attr(target_os = "macos", repr(C, packed))]
 pub struct SCARD_READERSTATE {
     pub szReader: *const c_char,
     pub pvUserData: *mut c_void,
RokLenarcic commented 7 years ago

It works. Interestingly if I slide the card in and out quickly I sometimes get a status update where the CHANGED flag is missing.

"Gemalto PC Twin Reader" STATE_CHANGED | STATE_PRESENT

"Gemalto PC Twin Reader" STATE_CHANGED | STATE_EMPTY

"Gemalto PC Twin Reader" STATE_EMPTY

"Gemalto PC Twin Reader" STATE_CHANGED | STATE_PRESENT
RokLenarcic commented 7 years ago

Well the example that doesn't work correctly remaining is the cancel one. Reports a normal exit instead of timeout.

Blocking call exited normally
bluetech commented 7 years ago

Great! I pushed this fix.

The article I linked to before (https://ludovicrousseau.blogspot.co.il/2015/12/os-x-el-capitan-missing-feature.html) says that \\?PnP?\Notification is not supported on macOS. I wonder if this is fixed nowadays? Can the monitor detect reader insertions & removals (the reader itself, not a card within a reader).

About the missing CHANGED, this seems reasonable the state hasn't changed from the previous one (STATE_EMPTY). I guess spurious wakeups are possible.

Well the example that doesn't work correctly remaining is the cancel one.

It actually doesn't work for me either now! Let me see what's going on (I wish it was possible to have tests for this... Maybe with qemu).

RokLenarcic commented 7 years ago

I tried monitor again and I got this:

Adding "Gemalto PC Twin Reader"

"Gemalto PC Twin Reader" STATE_CHANGED | STATE_PRESENT
Removing "\\\\?PnP?\\Notification"

I have the reader connected with the card in.

Here's 3 different scenarios, from here on out, that make it panic:

Second:

Third:

Removing "Gemalto PC Twin Reader"
Removing "Gemalto PC Twin Reader"
thread 'main' panicked at 'slice index starts at 1 but ends at 0', src/libcore/slice/mod.rs:678
stack backtrace:
   0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace
   1: std::panicking::default_hook::{{closure}}
   2: std::panicking::default_hook
   3: std::panicking::rust_panic_with_hook
   4: std::panicking::begin_panic
   5: std::panicking::begin_panic_fmt
   6: rust_begin_unwind
   7: core::panicking::panic_fmt
   8: core::slice::slice_index_order_fail
   9: <core::ops::Range<usize> as core::slice::SliceIndex<[T]>>::index
  10: <core::ops::RangeFrom<usize> as core::slice::SliceIndex<[T]>>::index
  11: core::slice::<impl core::ops::Index<I> for [T]>::index
  12: <collections::vec::Vec<T> as core::ops::Index<core::ops::RangeFrom<usize>>>::index
  13: monitor::main
  14: __rust_maybe_catch_panic
  15: std::rt::lang_start
  16: main
bluetech commented 7 years ago

I was able to reproduce the cancel problem in C as well. Something must have changed. I sent a question to the pcsclite mailing list, maybe they can tell what's going on: http://lists.alioth.debian.org/pipermail/pcsclite-muscle/2017-June/000921.html

As for the panics, they do not reproduce on linux/pcsclite. I suspect the problem is that the PNP_NOTIFICATION reader state, which the program assumes is always at position zero, returns is_dead -> true, then is removed from the vector, and then this panics: reader_states[1..].

To verify this, can you try this diff, and paste the output of one of the scenarios you mentioned?

diff --git a/pcsc/examples/monitor.rs b/pcsc/examples/monitor.rs
index ee5bd81..3fba4df 100644
--- a/pcsc/examples/monitor.rs
+++ b/pcsc/examples/monitor.rs
@@ -27,7 +27,7 @@ fn main() {
         // Add new readers.
         let names = ctx.list_readers(&mut readers_buf).expect("failed to list readers");
         for name in names {
-            if !reader_states[1..].iter().any(|rs| rs.name() == name) {
+            if !reader_states.iter().any(|rs| rs.name() == name) {
                 println!("Adding {:?}", name);
                 reader_states.push(ReaderState::new(name, STATE_UNAWARE));
             }
@@ -43,7 +43,7 @@ fn main() {

         // Print current state.
         println!();
-        for rs in &reader_states[1..] {
+        for rs in &reader_states {
             println!("{:?} {:?}", rs.name(), rs.event_state());
         }
     }

Also, if possible, run it in debug mode; this makes stacktraces a bit more readable.

Thanks!

RokLenarcic commented 7 years ago

Your patch makes it work.

bluetech commented 7 years ago

OK, I fixed the panics.

I'll close this issue now, and open a separate issue to track the cancel problem. I'll release 0.1.1 later today.

Thanks for reporting & debugging everything here. Let me know if you run into any other issues.