(면책 조항 :이 내용은 방대한 텍스트 벽이라는 것을 알고 있지만, 필자는 본질에 익숙해지기 위해 최선을 다했다. 매우 복잡한 질문입니다.맞춤 태그를 추가 할 때 _TIFFVGetField 구현에 혼란이 있음
저는이 질문에 이미 libtiff 메일 링리스트를 요청했지만, 라이브러리를 가지고 일하는 사람이 있으면 여기에 좋은 기회가있을 것이라고 생각했습니다.
내가 여기에 문서를 사용하여 라이브러리에 내 자신의 내장 된 태그를 추가하고 :
: 그래서 http://libtiff.maptools.org/addingtags.html를, 그래서 같이 tif_dirinfo.c의 상단에 정의 된 TIFFFieldInfo 배열에 항목을 추가
{ TIFFTAG_CUSTOM_XXX, 4, 4, TIFF_SLONG, FIELD_XXX, 1, 0, "XXX" },
내가 다음 tif_dir.h
에 정의 된 TIFFDirectory
구조에 필드를 추가 :
typedef struct {
/* ... */
int32 td_xxx[4];
} TIFFDirectory;
지금 내가 나서서 지시에 따라
_TIFFVSetField
및
_TIFFVGetField
을 수정했습니다. 이것이 내가 문제를 일으킨 곳입니다. 지금까지 내가 할 수있는
/* existing, standard tag for reference */
case TIFFTAG_YCBCRSUBSAMPLING:
*va_arg(ap, uint16*) = td->td_ycbcrsubsampling[0];
*va_arg(ap, uint16*) = td->td_ycbcrsubsampling[1];
break;
/* my new tag */
case TIFFTAG_CUSTOM_XXX:
*va_arg(ap, int32*) = td->td_xxx[0];
*va_arg(ap, int32*) = td->td_xxx[1];
*va_arg(ap, int32*) = td->td_xxx[2];
*va_arg(ap, int32*) = td->td_xxx[3];
break;
: 라이브러리에 이미 존재하는 패턴 (내가 뭐하는 거지 유사하다 TIFFTAG_YCBCRSUBSAMPLING
의 구현을 참조)를 흉내 낸
, 나는 _TIFFVGetField
에 다음 코드를 추가 이것이 완전히 틀렸다는 것을 말하십시오. int 배열을 기반으로 가변 인수 목록에 입력을 채우기위한 것입니다. 한 가지 유예의 축복은 va_list
에 제공된 인수가 항상 int32
유형이고 YcBr 코드가 int16
2 개를 사용한다는 것입니다. 그래서, 작동하지만, 그 구현을 복사 할 수 없습니다.
은 결국 TIFFWriteNormalTag
에서 tif_dirwrite.c
으로 호출됩니다.
case TIFF_LONG:
case TIFF_SLONG:
case TIFF_IFD:
if (fip->field_passcount) {
uint32* lp;
if (wc == (uint16) TIFF_VARIABLE2) {
TIFFGetField(tif, fip->field_tag, &wc2, &lp);
TDIRSetEntryCount(tif,dir, wc2);
} else { /* Assume TIFF_VARIABLE */
TIFFGetField(tif, fip->field_tag, &wc, &lp);
TDIRSetEntryCount(tif,dir, wc);
}
if (!TIFFWriteLongArray(tif, dir, lp))
return 0;
} else {
if (wc == 1) {
uint32 wp;
/* XXX handle LONG->SHORT conversion */
TIFFGetField(tif, fip->field_tag, &wp);
TDIRSetEntryOff(tif,dir, wp);
} else {
/* ---------------------------------------------------- */
/* this is the code that is called in my scenario */
/* ---------------------------------------------------- */
uint32* lp;
TIFFGetField(tif, fip->field_tag, &lp);
if (!TIFFWriteLongArray(tif, dir, lp))
return 0;
}
}
break;
그래서, 초기화되지 않은 포인터 lp
선언과 그 주소가 TIFFGetField
에 전달됩니다 : 관련 코드는 이것이다. 이것은 va_list (유일한 인수로 lp
)를 설정하고 TIFFVGetField
을 호출합니다. _TIFFVGetField
은 제공된 va_list
및 초기화되지 않은 포인터에 대한 포인터로 호출합니다.
여기에는 두 가지 문제가 있습니다. 도서관 이것은 잘못된 것
*va_arg(ap, int32*) = td->td_xxx[0];
(이미 존재하는 패턴을 다음 다시 내 코드 만) 데이터를 추출하는 방법을
첫째,이입니다. 원래 포인터를 int 값으로 설정합니다. 나는 아마도 (TIFFTAG_YCBCRSUBSAMPLING)을 따르는 예에서 이러한 정수는 실제로 주소라고 추론했다. 그래서 괜찮습니다.하지만 다른 문제가 있긴하지만 그 경우에도 마찬가지입니다.
라이브러리는 va_args
N
번을 호출합니다. 여기서 N
은 배열의 요소 수입니다. 내가 볼 수 있듯이 가변 인수 목록에는 단일 인수 (포인터의 주소) 만 포함됩니다.에 따라 추진으로 (실제 다음 인수이없는 경우, 또는 유형이 실제 다음 인수의 형태와 호환성이없는 경우
:이 정의되지 않은 (시작에서 중요한 비트) 표준에 따라 동작입니다 기본 인수 프로모션), 동작이 정의되지 않았습니다.
정확한 버전이 유효한 배열의 초기화 이전에 포인터를 설정
*va_arg(ap, int32**) = td_xxx;
것이다. 나는 그것이 복사본이 아닌 데이터 그 자체를 가리키고 있다는 점을 좋아하지 않는다. 적어도 충돌을 일으키지 않고 올바른 결과를 제공합니다.
여기 내 관심사는 미묘한 뭔가를 놓치고 있다는 것입니다. 이 소프트웨어는 오래되었고 많은 사람들이 사용했습니다. 따라서이 버그를 호출하는 것은 컴파일러에서 충돌을 비난하는 것처럼 느낍니다. 이는 입니다. 거의 항상 잘못되었습니다.
그러나 올바른 방법, 특히 라이브러리가 두 번 이상 호출 될 때 va_arg
이 반환하는 값에 대한 쓰기 방법을 추론 할 수는 없습니다.
도움을 주시면 감사하겠습니다. 미리 감사드립니다.