bool GetCallMemoryCopy(PEdgeCall *edge, Exp **target, Exp **source, Exp **length) { Variable *name = edge->GetDirectFunction(); if (!name) return false; MemcpyFunctionInfo *cur_memcpy = g_memcpy_functions; while (cur_memcpy->name) { if (TextNameMatch(name, cur_memcpy->name)) { *target = GetArgumentValue(cur_memcpy->target_arg); *source = GetArgumentValue(cur_memcpy->source_arg); *length = GetArgumentValue(cur_memcpy->length_arg); return true; } cur_memcpy++; } ReallocFunctionInfo *cur_realloc = g_realloc_functions; while (cur_realloc->name) { if (TextNameMatch(name, cur_realloc->name)) { *target = GetReturnedValue(); *source = GetArgumentValue(cur_realloc->base_arg); (*source)->IncRef(); *length = GetByteUpperBound(*source); return true; } cur_realloc++; } return false; }
bool GetAllocationFunction(Variable *name, Exp **object, Exp **size) { MallocFunctionInfo *cur_malloc = g_malloc_functions; while (cur_malloc->name) { if (TextNameMatch(name, cur_malloc->name)) { *object = GetReturnedValue(); *size = GetArgumentValue(cur_malloc->size_arg); return true; } cur_malloc++; } FixedMallocFunctionInfo *cur_fixed = g_fixed_malloc_functions; while (cur_fixed->name) { if (TextNameMatch(name, cur_fixed->name)) { *object = GetReturnedValue(); *size = Exp::MakeInt(cur_fixed->size); return true; } cur_fixed++; } CallocFunctionInfo *cur_calloc = g_calloc_functions; while (cur_calloc->name) { if (TextNameMatch(name, cur_calloc->name)) { Exp *size_one = GetArgumentValue(cur_calloc->size_arg_one); Exp *size_two = GetArgumentValue(cur_calloc->size_arg_two); *object = GetReturnedValue(); *size = Exp::MakeBinop(cur_calloc->binop, size_one, size_two); return true; } cur_calloc++; } return false; }
/* virtual */ OP_STATUS ES_JavascriptURLThread::EvaluateThread() { OP_STATUS ret = OpStatus::OK; switch (eval_state) { case STATE_INITIAL: { eval_state = STATE_SET_PROGRAM; #ifdef USER_JAVASCRIPT DOM_Environment *environment = scheduler->GetFramesDocument()->GetDOMEnvironment(); RETURN_IF_ERROR(environment->HandleJavascriptURL(this)); if (IsBlocked()) return OpStatus::OK; #endif // USER_JAVASCRIPT } // fall through case STATE_SET_PROGRAM: if (source) { ES_ProgramText program_text; program_text.program_text = source; program_text.program_text_length = uni_strlen(source); ES_Runtime *runtime = scheduler->GetRuntime(); ES_Program *program; OP_STATUS status; ES_Runtime::CompileProgramOptions options; options.generate_result = TRUE; options.global_scope = FALSE; options.script_type = SCRIPT_TYPE_JAVASCRIPT_URL; options.when = UNI_L("while loading"); options.script_url = &url; #ifdef ECMASCRIPT_DEBUGGER options.reformat_source = g_ecmaManager->GetWantReformatScript(runtime); #endif // ECMASCRIPT_DEBUGGER if (OpStatus::IsSuccess(status = runtime->CompileProgram(&program_text, 1, &program, options))) if (program) SetProgram(program); else status = OpStatus::ERR; if (OpStatus::IsMemoryError(status)) { is_completed = is_failed = TRUE; return status; } else if (OpStatus::IsError(status)) { is_completed = is_failed = TRUE; return OpStatus::OK; } } eval_state = STATE_EVALUATE; // fall through case STATE_EVALUATE: { ret = ES_Thread::EvaluateThread(); if (OpStatus::IsError(ret)) { eval_state = STATE_HANDLE_RESULT; is_completed = TRUE; break; } else if (IsCompleted()) { if (IsFailed()) { eval_state = STATE_DONE; break; } else #ifdef USER_JAVASCRIPT eval_state = STATE_SEND_USER_JS_AFTER; #else // USER_JAVASCRIPT eval_state = STATE_HANDLE_RESULT; #endif // USER_JAVASCRIPT } else break; } // fall through #ifdef USER_JAVASCRIPT case STATE_SEND_USER_JS_AFTER: { DOM_Environment *environment = scheduler->GetFramesDocument()->GetDOMEnvironment(); RETURN_IF_ERROR(environment->HandleJavascriptURLFinished(this)); eval_state = STATE_HANDLE_RESULT; if (IsBlocked()) { is_completed = FALSE; break; } } // fall through #endif // USER_JAVASCRIPT case STATE_HANDLE_RESULT: { is_completed = TRUE; const uni_char *use_result = NULL; #ifdef USER_JAVASCRIPT if (has_result) use_result = result; else #endif // USER_JAVASCRIPT if (ReturnedValue()) { ES_Value return_value; RETURN_IF_ERROR(GetReturnedValue(&return_value)); if (return_value.type == VALUE_STRING) use_result = return_value.value.string; } FramesDocument *frames_doc = GetFramesDocument(); OP_ASSERT(frames_doc); // Since we're executing we must be in a document if (use_result) { if (write_result_to_document) { // The HTML5 spec says that we should load this data exactly as if it had come // from an HTTP connection with content type text/html and status 200. This // is a very bad approximation of that. BOOL is_busy = scheduler->IsDraining() || !frames_doc->IsCurrentDoc(); write_result_to_document = FALSE; // Since it's enough to do it once frames_doc->SetWaitForJavascriptURL(FALSE); if (!is_busy) if (HLDocProfile *hld_profile = frames_doc->GetHLDocProfile()) is_busy = hld_profile->GetESLoadManager()->GetScriptGeneratingDoc(); if (!is_busy) { if (GetOriginInfo().open_in_new_window) RETURN_IF_ERROR(DOM_Environment::OpenWindowWithData(use_result, frames_doc, this, GetOriginInfo().is_user_requested)); else { // The ESOpen()/ESClose() calls are just done in order to create an // empty document in The Right Way(tm) in order to parse some data // into it as if it had been loaded from a URL, and not to set up // a document.write call like they are usually used for. ESDocException doc_exception; // Ignored RETURN_IF_ERROR(frames_doc->ESOpen(scheduler->GetRuntime(), &url, is_reload, NULL, NULL, &doc_exception)); FramesDocument *new_frames_doc = frames_doc->GetDocManager()->GetCurrentDoc(); RETURN_IF_ERROR(new_frames_doc->ESClose(scheduler->GetRuntime())); SetBlockType(ES_BLOCK_NONE); if (frames_doc != new_frames_doc) RETURN_IF_ERROR(new_frames_doc->GetLogicalDocument()->ParseHtmlFromString(use_result, uni_strlen(use_result), FALSE, FALSE, FALSE)); else OP_ASSERT(!"ESOpen might have failed, but if it didn't then we're stuck with a hung thread in a document and nothing will work"); new_frames_doc->ESStoppedGeneratingDocument(); } } } if (write_result_to_url) { if (want_utf8) { UTF16toUTF8Converter converter; unsigned length = uni_strlen(use_result) * sizeof source[0], needed = converter.BytesNeeded(use_result, length); converter.Reset(); char *data; if (needed < g_memory_manager->GetTempBufLen()) data = (char *) g_memory_manager->GetTempBuf(); else data = OP_NEWA(char, needed); if (!data) { ret = OpStatus::ERR_NO_MEMORY; break; } else { int read, written = converter.Convert(use_result, length, data, needed, &read); url.WriteDocumentData(URL::KNormal, data, written); url.WriteDocumentDataFinished(); if (data != g_memory_manager->GetTempBuf()) OP_DELETEA(data); } } else { url.WriteDocumentData(URL::KNormal, use_result, uni_strlen(use_result)); url.WriteDocumentDataFinished(); } } } else if (write_result_to_document) { // The HTML5 spec says this should be handled as a HTTP status 204, NO_CONTENT frames_doc->GetMessageHandler()->PostMessage(MSG_URL_LOADING_FAILED, url.Id(), DH_ERRSTR(SI,ERR_HTTP_NO_CONTENT)); frames_doc->SetWaitForJavascriptURL(FALSE); write_result_to_document = FALSE; // Since it's done and we don't want to do it again. } eval_state = STATE_DONE; }
void FillBakedSummary(BlockSummary *sum) { Variable *name = sum->GetId()->BaseVar(); // primitive memory allocator. Exp *object; Exp *size; if (GetAllocationFunction(name, &object, &size)) { Exp *bound = GetByteUpperBound(object); // the upper bound is greater or equal to zero. bound->IncRef(); Exp *zero = Exp::MakeInt(0); Bit *bound_nonneg = Exp::MakeCompareBit(B_GreaterEqual, bound, zero); sum->AddAssume(bound_nonneg); // the upper bound of the object is exactly equal to size. Bit *bound_equal = Exp::MakeCompareBit(B_Equal, bound, size); sum->AddAssume(bound_equal); // TODO: it would be nice to assert the offset is exactly equal // to zero for the UI; however, this can lead to spurious contradiction // if unaligned pointers are in use. } // return value bears some relation with an argument. ReturnCompareFunctionInfo *cur_return = g_return_compare_functions; while (cur_return->name) { if (TextNameMatch(name, cur_return->name)) { Exp *ret_exp = GetReturnedValue(); Exp *arg_exp = GetArgumentValue(cur_return->compare_arg); Type *type = NULL; if (IsPointerBinop(cur_return->binop)) type = Type::MakeInt(1, true); Bit *bit = Exp::MakeCompareBit(cur_return->binop, ret_exp, arg_exp, type); sum->AddAssume(bit); } cur_return++; } // return value is NULL terminated. const char **cur_ret_term = g_return_terminated_functions; while (*cur_ret_term) { if (TextNameMatch(name, *cur_ret_term)) { Exp *ret_exp = GetReturnedValue(); Exp *terminate = GetNullTerminate(ret_exp); Exp *zero = Exp::MakeInt(0); Bit *bit = Exp::MakeCompareBit(B_GreaterEqual, terminate, zero); sum->AddAssume(bit); } cur_ret_term++; } // an argument is NULL terminated. TerminateFunctionInfo *cur_term = g_terminate_functions; while (cur_term->name) { if (TextNameMatch(name, cur_term->name) && cur_term->terminates) { Exp *arg_exp = GetArgumentValue(cur_term->terminate_arg); Exp *kind = GetNullTerminate(NULL); Exp *exit_term = Exp::MakeExit(arg_exp, kind); Exp *zero = Exp::MakeInt(0); Bit *bit = Exp::MakeCompareBit(B_GreaterEqual, exit_term, zero); sum->AddAssume(bit); } cur_term++; } // strchr constraint: char_arg != 0 => zterm(ret) > 0. StrchrFunctionInfo *cur_strchr = g_strchr_functions; while (cur_strchr->name) { if (TextNameMatch(name, cur_strchr->name)) { Exp *arg_exp = GetArgumentValue(cur_strchr->char_arg); Exp *ret_exp = GetReturnedValue(); Exp *terminate = GetNullTerminate(ret_exp); Exp *zero = Exp::MakeInt(0); zero->IncRef(); Bit *left = Exp::MakeCompareBit(B_NotEqual, arg_exp, zero); Bit *right = Exp::MakeCompareBit(B_GreaterThan, terminate, zero); Bit *bit = Bit::MakeImply(left, right); sum->AddAssume(bit); } cur_strchr++; } // strlen constraint: ret >= 0 && ret == zterm(arg) StrlenFunctionInfo *cur_strlen = g_strlen_functions; while (cur_strlen->name) { if (TextNameMatch(name, cur_strlen->name)) { Exp *arg_exp = GetArgumentValue(cur_strlen->string_arg); Exp *retval = GetReturnedValue(); Exp *terminate = GetNullTerminate(arg_exp); retval->IncRef(); Exp *zero = Exp::MakeInt(0); Bit *ge_zero = Exp::MakeCompareBit(B_GreaterEqual, retval, zero); sum->AddAssume(ge_zero); Bit *eq_term = Exp::MakeCompareBit(B_Equal, retval, terminate); sum->AddAssume(eq_term); } cur_strlen++; } // strcmp constraint: ret == 0 ==> zterm(arg_one) == zterm(arg_two) StrcmpFunctionInfo *cur_strcmp = g_strcmp_functions; while (cur_strcmp->name) { if (TextNameMatch(name, cur_strcmp->name)) { Exp *arg_one_exp = GetArgumentValue(cur_strcmp->string_arg_one); Exp *arg_two_exp = GetArgumentValue(cur_strcmp->string_arg_two); Exp *retval = GetReturnedValue(); Exp *terminate_one = GetNullTerminate(arg_one_exp); Exp *terminate_two = GetNullTerminate(arg_two_exp); Exp *zero = Exp::MakeInt(0); Bit *left = Exp::MakeCompareBit(B_Equal, retval, zero); Bit *right = Exp::MakeCompareBit(B_Equal, terminate_one, terminate_two); Bit *bit = Bit::MakeImply(left, right); sum->AddAssume(bit); } cur_strcmp++; } // strncmp constraint: ret == 0 ==> (zterm(arg_one) == zterm(arg_two) // || (zterm(arg_one) >= length_arg && // zterm(arg_two) >= length_arg)) StrncmpFunctionInfo *cur_strncmp = g_strncmp_functions; while (cur_strncmp->name) { if (TextNameMatch(name, cur_strncmp->name)) { Exp *arg_one_exp = GetArgumentValue(cur_strncmp->string_arg_one); Exp *arg_two_exp = GetArgumentValue(cur_strncmp->string_arg_two); Exp *length_exp = GetArgumentValue(cur_strncmp->length_arg); Exp *retval = GetReturnedValue(); Exp *terminate_one = GetNullTerminate(arg_one_exp); Exp *terminate_two = GetNullTerminate(arg_two_exp); Exp *zero = Exp::MakeInt(0); terminate_one->IncRef(); terminate_two->IncRef(); length_exp->IncRef(); Bit *left = Exp::MakeCompareBit(B_Equal, retval, zero); Bit *term_eq = Exp::MakeCompareBit(B_Equal, terminate_one, terminate_two); Bit *ge_one = Exp::MakeCompareBit(B_GreaterEqual, terminate_one, length_exp); Bit *ge_two = Exp::MakeCompareBit(B_GreaterEqual, terminate_two, length_exp); Bit *ge_both = Bit::MakeAnd(ge_one, ge_two); Bit *right = Bit::MakeOr(term_eq, ge_both); Bit *bit = Bit::MakeImply(left, right); sum->AddAssume(bit); } cur_strncmp++; } }