From 768f8650353021bacf16ed7c7d49a0ddef87eaf9 Mon Sep 17 00:00:00 2001 From: hanna Date: Sat, 14 Nov 2009 22:57:16 +0000 Subject: [PATCH] Bulletproofing code. If errors are encountering during the run, turn them into JDK exceptions whenever possible instead of random core dumps. Don't allow negative values for most of the 'bwa aln' input parameters. git-svn-id: file:///humgen/gsa-scr1/gsa-engineering/svn_contents/trunk@2049 348d0f76-0448-11de-a6fe-93d51630548a --- ...tute_sting_alignment_bwa_c_BWACAligner.cpp | 135 +++++++++++++++--- 1 file changed, 119 insertions(+), 16 deletions(-) diff --git a/c/bwa/org_broadinstitute_sting_alignment_bwa_c_BWACAligner.cpp b/c/bwa/org_broadinstitute_sting_alignment_bwa_c_BWACAligner.cpp index 3e07a623a..77451b86e 100644 --- a/c/bwa/org_broadinstitute_sting_alignment_bwa_c_BWACAligner.cpp +++ b/c/bwa/org_broadinstitute_sting_alignment_bwa_c_BWACAligner.cpp @@ -8,35 +8,45 @@ #include "bwa_gateway.h" #include "org_broadinstitute_sting_alignment_bwa_c_BWACAligner.h" -static jclass java_alignment_array_class = NULL; -static jclass java_alignment_class = NULL; -static jmethodID java_alignment_constructor = NULL; - typedef void (BWA::*int_setter)(int value); typedef void (BWA::*float_setter)(float value); static jstring get_configuration_string(JNIEnv* env, jobject configuration, const char* field_name); - static void set_int_configuration_param(JNIEnv* env, jobject configuration, const char* field_name, BWA* bwa, int_setter setter); static void set_float_configuration_param(JNIEnv* env, jobject configuration, const char* field_name, BWA* bwa, float_setter setter); +static void throw_config_value_exception(JNIEnv* env, const char* field_name, const char* message); JNIEXPORT jlong JNICALL Java_org_broadinstitute_sting_alignment_bwa_c_BWACAligner_create(JNIEnv* env, jobject instance, jobject configuration) { jstring java_ann = get_configuration_string(env,configuration,"annFileName"); + if(env->ExceptionCheck()) return 0L; jstring java_amb = get_configuration_string(env,configuration,"ambFileName"); + if(env->ExceptionCheck()) return 0L; jstring java_pac = get_configuration_string(env,configuration,"pacFileName"); + if(env->ExceptionCheck()) return 0L; jstring java_forward_bwt = get_configuration_string(env,configuration,"forwardBWTFileName"); + if(env->ExceptionCheck()) return 0L; jstring java_forward_sa = get_configuration_string(env,configuration,"forwardSAFileName"); + if(env->ExceptionCheck()) return 0L; jstring java_reverse_bwt = get_configuration_string(env,configuration,"reverseBWTFileName"); + if(env->ExceptionCheck()) return 0L; jstring java_reverse_sa = get_configuration_string(env,configuration,"reverseSAFileName"); + if(env->ExceptionCheck()) return 0L; const char* ann_filename = env->GetStringUTFChars(java_ann,JNI_FALSE); + if(env->ExceptionCheck()) return 0L; const char* amb_filename = env->GetStringUTFChars(java_amb,JNI_FALSE); + if(env->ExceptionCheck()) return 0L; const char* pac_filename = env->GetStringUTFChars(java_pac,JNI_FALSE); + if(env->ExceptionCheck()) return 0L; const char* forward_bwt_filename = env->GetStringUTFChars(java_forward_bwt,JNI_FALSE); + if(env->ExceptionCheck()) return 0L; const char* forward_sa_filename = env->GetStringUTFChars(java_forward_sa,JNI_FALSE); + if(env->ExceptionCheck()) return 0L; const char* reverse_bwt_filename = env->GetStringUTFChars(java_reverse_bwt,JNI_FALSE); + if(env->ExceptionCheck()) return 0L; const char* reverse_sa_filename = env->GetStringUTFChars(java_reverse_sa,JNI_FALSE); + if(env->ExceptionCheck()) return 0L; BWA* bwa = new BWA(ann_filename, amb_filename, @@ -47,25 +57,34 @@ JNIEXPORT jlong JNICALL Java_org_broadinstitute_sting_alignment_bwa_c_BWACAligne reverse_sa_filename); set_float_configuration_param(env, configuration, "maximumEditDistance", bwa, &BWA::set_max_edit_distance); + if(env->ExceptionCheck()) return 0L; set_int_configuration_param(env, configuration, "maximumGapOpens", bwa, &BWA::set_max_gap_opens); + if(env->ExceptionCheck()) return 0L; set_int_configuration_param(env, configuration, "maximumGapExtensions", bwa, &BWA::set_max_gap_extensions); + if(env->ExceptionCheck()) return 0L; set_int_configuration_param(env, configuration, "disallowIndelWithinRange", bwa, &BWA::set_disallow_indel_within_range); + if(env->ExceptionCheck()) return 0L; set_int_configuration_param(env, configuration, "mismatchPenalty", bwa, &BWA::set_mismatch_penalty); + if(env->ExceptionCheck()) return 0L; set_int_configuration_param(env, configuration, "gapOpenPenalty", bwa, &BWA::set_gap_open_penalty); + if(env->ExceptionCheck()) return 0L; set_int_configuration_param(env, configuration, "gapExtensionPenalty", bwa, &BWA::set_gap_extension_penalty); + if(env->ExceptionCheck()) return 0L; env->ReleaseStringUTFChars(java_ann,ann_filename); + if(env->ExceptionCheck()) return 0L; env->ReleaseStringUTFChars(java_amb,amb_filename); + if(env->ExceptionCheck()) return 0L; env->ReleaseStringUTFChars(java_pac,pac_filename); + if(env->ExceptionCheck()) return 0L; env->ReleaseStringUTFChars(java_forward_bwt,forward_bwt_filename); + if(env->ExceptionCheck()) return 0L; env->ReleaseStringUTFChars(java_forward_sa,forward_sa_filename); + if(env->ExceptionCheck()) return 0L; env->ReleaseStringUTFChars(java_reverse_bwt,reverse_bwt_filename); + if(env->ExceptionCheck()) return 0L; env->ReleaseStringUTFChars(java_reverse_sa,reverse_sa_filename); - - // Cache the class object for an array of alignments. - java_alignment_array_class = env->FindClass("[Lorg/broadinstitute/sting/alignment/Alignment;"); - java_alignment_class = env->FindClass("org/broadinstitute/sting/alignment/Alignment"); - java_alignment_constructor = env->GetMethodID(java_alignment_class, "", "(IIZI[C[I)V"); + if(env->ExceptionCheck()) return 0L; return (jlong)bwa; } @@ -76,17 +95,23 @@ JNIEXPORT void JNICALL Java_org_broadinstitute_sting_alignment_bwa_c_BWACAligner delete bwa; } -JNIEXPORT jobjectArray JNICALL Java_org_broadinstitute_sting_alignment_bwa_c_BWACAligner_getAlignments(JNIEnv* env, jobject object, jlong java_bwa, jbyteArray java_bases) { +JNIEXPORT jobjectArray JNICALL Java_org_broadinstitute_sting_alignment_bwa_c_BWACAligner_getAlignments(JNIEnv* env, jobject object, jlong java_bwa, jbyteArray java_bases) +{ BWA* bwa = (BWA*)java_bwa; const jsize read_length = env->GetArrayLength(java_bases); + if(env->ExceptionCheck()) return NULL; + jbyte *read_bases = env->GetByteArrayElements(java_bases,JNI_FALSE); + if(read_bases == NULL) return NULL; Alignment* alignments = NULL; unsigned num_alignments = 0; + bwa->align((const char*)read_bases,read_length,alignments,num_alignments); jobjectArray java_alignments = env->NewObjectArray(num_alignments, env->FindClass("org/broadinstitute/sting/alignment/Alignment"), NULL); + if(java_alignments == NULL) return NULL; for(unsigned alignment_idx = 0; alignment_idx < (unsigned)num_alignments; alignment_idx++) { Alignment& alignment = *(alignments + alignment_idx); @@ -97,26 +122,37 @@ JNIEXPORT jobjectArray JNICALL Java_org_broadinstitute_sting_alignment_bwa_c_BWA else cigar_length = alignment.n_cigar; jcharArray java_cigar_operators = env->NewCharArray(cigar_length); + if(java_cigar_operators == NULL) return NULL; jintArray java_cigar_lengths = env->NewIntArray(cigar_length); + if(java_cigar_lengths == NULL) return NULL; if(alignment.cigar) { for(unsigned cigar_idx = 0; cigar_idx < (unsigned)alignment.n_cigar; ++cigar_idx) { jchar cigar_operator = "MIDS"[alignment.cigar[cigar_idx]>>14]; jint cigar_length = alignment.cigar[cigar_idx]&0x3fff; + env->SetCharArrayRegion(java_cigar_operators,cigar_idx,1,&cigar_operator); + if(env->ExceptionCheck()) return NULL; env->SetIntArrayRegion(java_cigar_lengths,cigar_idx,1,&cigar_length); + if(env->ExceptionCheck()) return NULL; } } else { if(alignment.type != BWA_TYPE_NO_MATCH) { jchar cigar_operator = 'M'; env->SetCharArrayRegion(java_cigar_operators,0,1,&cigar_operator); + if(env->ExceptionCheck()) return NULL; env->SetIntArrayRegion(java_cigar_lengths,0,1,&read_length); + if(env->ExceptionCheck()) return NULL; } } jclass java_alignment_class = env->FindClass("org/broadinstitute/sting/alignment/Alignment"); + if(java_alignment_class == NULL) return NULL; + jmethodID java_alignment_constructor = env->GetMethodID(java_alignment_class, "", "(IIZI[C[I)V"); + if(java_alignment_constructor == NULL) return NULL; + jobject java_alignment = env->NewObject(java_alignment_class, java_alignment_constructor, alignment.contig, @@ -125,44 +161,111 @@ JNIEXPORT jobjectArray JNICALL Java_org_broadinstitute_sting_alignment_bwa_c_BWA alignment.mapQ, java_cigar_operators, java_cigar_lengths); - env->SetObjectArrayElement(java_alignments,alignment_idx,java_alignment); + if(java_alignment == NULL) return NULL; delete[] alignment.cigar; + + env->SetObjectArrayElement(java_alignments,alignment_idx,java_alignment); + if(env->ExceptionCheck()) return NULL; + + env->DeleteLocalRef(java_alignment_class); + if(env->ExceptionCheck()) return NULL; } delete[] alignments; - env->ReleaseByteArrayElements(java_bases,read_bases,0); + env->ReleaseByteArrayElements(java_bases,read_bases,JNI_FALSE); - return java_alignments; + return env->ExceptionCheck() ? NULL : java_alignments; } static jstring get_configuration_string(JNIEnv* env, jobject configuration, const char* field_name) { jclass configuration_class = env->GetObjectClass(configuration); + if(configuration_class == NULL) return NULL; + jfieldID configuration_field = env->GetFieldID(configuration_class, field_name, "Ljava/lang/String;"); - return (jstring)env->GetObjectField(configuration,configuration_field); + if(configuration_field == NULL) return NULL; + + jstring result = (jstring)env->GetObjectField(configuration,configuration_field); + env->DeleteLocalRef(configuration_class); + return result; } static void set_int_configuration_param(JNIEnv* env, jobject configuration, const char* field_name, BWA* bwa, int_setter setter) { jclass configuration_class = env->GetObjectClass(configuration); + if(configuration_class == NULL) return; + jfieldID configuration_field = env->GetFieldID(configuration_class, field_name, "Ljava/lang/Integer;"); + if(configuration_field == NULL) return; + jobject boxed_value = env->GetObjectField(configuration,configuration_field); + if(env->ExceptionCheck()) return; + if(boxed_value != NULL) { jclass int_box_class = env->FindClass("java/lang/Integer"); + if(int_box_class == NULL) return; + jmethodID int_extractor = env->GetMethodID(int_box_class,"intValue", "()I"); + if(int_extractor == NULL) return; + jint value = env->CallIntMethod(boxed_value,int_extractor); + if(env->ExceptionCheck()) return; + + if(value < 0) + { + throw_config_value_exception(env,field_name,"cannot be set to a negative value"); + return; + } + (bwa->*setter)(value); + + env->DeleteLocalRef(int_box_class); } + + env->DeleteLocalRef(boxed_value); + env->DeleteLocalRef(configuration_class); } -static void set_float_configuration_param(JNIEnv* env, jobject configuration, const char* field_name, BWA* bwa, float_setter setter) { +static void set_float_configuration_param(JNIEnv* env, jobject configuration, const char* field_name, BWA* bwa, float_setter setter) +{ jclass configuration_class = env->GetObjectClass(configuration); + if(configuration_class == NULL) return; + jfieldID configuration_field = env->GetFieldID(configuration_class, field_name, "Ljava/lang/Float;"); + if(configuration_field == NULL) return; + jobject boxed_value = env->GetObjectField(configuration,configuration_field); if(boxed_value != NULL) { jclass float_box_class = env->FindClass("java/lang/Float"); + if(float_box_class == NULL) return; + jmethodID float_extractor = env->GetMethodID(float_box_class,"floatValue", "()F"); + if(float_extractor == NULL) return; + jfloat value = env->CallFloatMethod(boxed_value,float_extractor); + if(env->ExceptionCheck()) return; + + if(value < 0) + { + throw_config_value_exception(env,field_name,"cannot be set to a negative value"); + return; + } + (bwa->*setter)(value); + + env->DeleteLocalRef(float_box_class); } + + env->DeleteLocalRef(boxed_value); + env->DeleteLocalRef(configuration_class); +} + +static void throw_config_value_exception(JNIEnv* env, const char* field_name, const char* message) +{ + char* buffer = new char[strlen(field_name)+1+strlen(message)+1]; + sprintf(buffer,"%s %s",field_name,message); + jclass sting_exception_class = env->FindClass("org/broadinstitute/sting/utils/StingException"); + if(sting_exception_class == NULL) return; + env->ThrowNew(sting_exception_class, buffer); + delete[] buffer; }