2012-01-24 23 views
13

Từ một BSTR chỉ là một typedef cho wchar_t* cơ sở mã của chúng tôi có một số (nhiều?) Nơi literals chuỗi được truyền đến một phương pháp mong đợi một BSTR lon này mess lên với marshallers hoặc bất kỳ ai cố gắng sử dụng bất kỳ phương thức cụ thể nào (ví dụ: SysStringLen) BSTR.tĩnh phân tích mã để phát hiện thông qua một wchar_t * để BSTR

Có cách nào để phát hiện tĩnh loại lạm dụng này không?

tôi đã cố gắng biên soạn với VC10 /Wall và với tĩnh phân tích mã Microsoft Tất cả quy tắc nhưng mảnh vi phạm mã sau đây không được đánh dấu bởi một trong hai trong số họ.

void foo(BSTR str) 
{ 
    std::cout << SysStringLen(str) << std::endl; 
} 

int _tmain() 
{ 
    foo(L"Don't do that"); 
} 

Cập nhật: Sau khi cố gắng phá hoại wtypes.h vào việc phát hiện các loại tội lỗi tôi đã từ bỏ.

Tôi đã thử hai đường dẫn, cả hai đều phải làm việc với chương trình mẫu của mình ở trên nhưng một khi tôi đã thử một dự án thực sự thì chúng không thành công.

  1. tạo ra một lớp tên là BSTR nhưng vì một VARIANTBSTR như một thành viên công đoàn các lớp mới không thể có bất kỳ nhà thầu hoặc nhà khai thác nhiệm vụ này đã phá vỡ mọi nơi được NULL được đối xử như một BSTR. Tôi đã cố gắng thay thế NULL bằng một loại có toán tử chuyển đổi nhưng sau khi thêm hàng tá toán tử mới (so sánh, chuyển đổi, v.v.) tôi bắt đầu chạy vào các cuộc gọi mơ hồ và bỏ cuộc.
  2. Sau đó, tôi đã thử cách được đề xuất bởi @CashCow và @Hans (tạo BSTR a typedef cho một loại con trỏ khác). Điều đó không có tác dụng, sau khi thêm toBSTRfromBSTR phương pháp và xả rác comutil.h (_bstr_t) và các địa điểm khác có chuyển đổi cuối cùng tôi đã đến lúc trình biên dịch bị nghẹn ở tiêu đề được tạo từ IDL (giá trị mặc định được dịch sang chữ) chuỗi rộng).

Tóm lại tôi đã từ bỏ việc tự mình thực hiện điều này, nếu có ai biết về công cụ phân tích mã có thể giúp tôi rất vui khi được nghe về nó.

+2

BSTR có thể là một typedef nhưng điều đó không có nghĩa là đó là chuỗi bị hủy. Chuỗi đại diện của nó thực sự là sinh vật với ký tự wchar_t thứ 3, 2 đầu tiên là tiền tố chiều dài (do đó cho phép độ dài tối đa 0xFFFF). Chúng có thể chứa các giá trị rỗng được nhúng. Tôi nghĩ rằng họ thường là null chấm dứt. – CashCow

+3

@CashCow, không chính xác, độ dài được đặt * trước * dữ liệu thực tế (đây là những gì 'SysStringLen' tìm) là lý do tại sao nó không chính xác để xử lý' wchar_t * 'là' BSTR'. – Motti

+0

Có, độ dài trước dữ liệu. Khi bạn gọi SysAllocString nó trả về cho bạn byte thứ 5. Khi bạn vượt qua trong một BSTR bạn vượt qua trong địa chỉ của byte được phân bổ thứ 5. – CashCow

Trả lời

3

Tôi tin rằng Coverity xác nhận quyền sở hữu để phát hiện các loại lỗ hổng này. Tôi nhớ họ đề cập đến công cụ COM cụ thể khi họ demo'd đến một công ty tôi đã làm việc cho.

Họ datasheet chắc chắn dường như ngụ ý rằng họ kiểm tra các lớp sử dụng BSTR không đúng cách. Họ có một giai đoạn demo; bạn có thể thử nó và xem nó có gắn cờ đầu vào mẫu của bạn hay không.

+0

Sau khi kiểm tra, tôi thấy rằng 'COM.BSTR.CONV' phát hiện mẫu này, cảm ơn! – Motti

1

Thay vào đó, bạn có thể thay đổi phương pháp của mình để sử dụng _bstr_t hoặc CComBSTR không?

Nếu sau đó không phải là một nghĩa đen về mặt kỹ thuật là const wchar_t *, nếu có cài đặt trình biên dịch không cho phép chuyển đổi con trỏ - không phải const thì bạn có thể làm điều đó.

Nếu không, có khả năng sửa đổi định nghĩa BSTR thành dấu * ngắn. Sau đó, nếu bạn xây dựng tất cả các nguồn của bạn, bạn sẽ nhận được lỗi trình biên dịch bất cứ nơi nào một chữ đang được thông qua và bạn có thể sửa chữa tất cả các mã này. Sau đó, tôi khuyên bạn nên thay đổi lại ...

+0

Không có nhiều trong số đó là các phương thức COM thuần túy. – Motti

+0

Tùy chọn 2 (ngăn chặn chuyển đổi từ 'const wchar_t *') là không đủ vì không phải tất cả các cá thể đều là chuỗi ký tự. Tùy chọn 3 ('typedef unsigned short * BSTR') sẽ không hoạt động vì đôi khi chúng ta chuyển' BSTR' sang 'wcscmp' (et al.) Không chấp nhận' unsigned short * ' – Motti

0

Vượt quá tất cả các chức năng bằng BSTR và chuyển tiếp chúng với chuyển đổi thích hợp.

void foo(BSTR str) 
{ 
    std::cout << SysStringLen(str) << std::endl; 
} 

void foo(const WCHAR *str) 
{ 
    foo(SysAllocString(str)); 
} 

int _tmain() 
{ 
    foo(L"don't do this"); 
    return 0; 
} 

Hoặc, để tạo ra lỗi biên dịch, thay đổi tất cả các loại tham số từ BSTR đến cái gì khác và tìm kiếm các lỗi:

typedef UINT bar; 

void foo(bar _str) 
{ 
    // make the compiler happy below 
    BSTR str = (BSTR)_str; 
    std::cout << SysStringLen(str) << std::endl; 
} 

int _tmain() 
{ 
    foo(L"don't do this"); 
    foo((bar)42); 
    return 0; 
} 

lỗi C2664: 'foo': không thể chuyển đổi thông số 1 từ 'const wchar_t [14]' thành 'bar'

Tôi giả định lỗi C2664 và loại 'const wchar_t []' được trình biên dịch xác định là những gì bạn muốn trình biên dịch tìm cho mọi cuộc gọi nội bộ được thực hiện cho chức năng bằng cách sử dụng BSTR?

1

Bạn có thể thử biên dịch bằng Clang, phân tích tĩnh/động có thể tìm thấy những gì bạn đang tìm kiếm.

+0

Clang có hỗ trợ biên dịch C++ của Microsoft không ? – Motti

+0

Khá chắc chắn nó hiện nay, và liên tục cải thiện. – ticktock

Các vấn đề liên quan