diff --git a/Makefile b/Makefile
index fb909f46afab84a40328ffe9eed296856317cfb0..9f8f99e9b5e3a794996712a698fed3660a7053c8 100644
--- a/Makefile
+++ b/Makefile
@@ -904,11 +904,10 @@ PLUGIN_CMO:= partitioning/split_strategy domains/domain_mode value_parameters \
 	partitioning/partitioning_index partitioning/trace_partitioning \
 	engine/mem_exec engine/iterator engine/initialization \
 	engine/compute_functions engine/analysis register \
-	api/general_requests \
-	utils/unit_tests \
-	api/values_request \
 	domains/taint_domain \
-	$(APRON_CMO) $(NUMERORS_CMO)
+	$(APRON_CMO) $(NUMERORS_CMO) \
+	api/general_requests api/values_request \
+	utils/unit_tests
 PLUGIN_CMI:= values/abstract_value values/abstract_location \
 	domains/abstract_domain domains/simpler_domains
 PLUGIN_DEPENDENCIES:=Callgraph LoopAnalysis RteGen Server
diff --git a/ivette/src/dome/renderer/controls/gallery.json b/ivette/src/dome/renderer/controls/gallery.json
index 62fe91ead33c03e2bd5b866519ffd02dfc3574a8..719e0b838040aa67305e87be0730254a02810214 100644
--- a/ivette/src/dome/renderer/controls/gallery.json
+++ b/ivette/src/dome/renderer/controls/gallery.json
@@ -368,5 +368,15 @@
     "title": "Package",
     "viewBox": "0 0 21 16",
     "path": "M5.714 14.571l3.429-1.714v-2.804l-3.429 1.464v3.054zM5.143 10.518l3.607-1.545-3.607-1.545-3.607 1.545zM14.857 14.571l3.429-1.714v-2.804l-3.429 1.464v3.054zM14.286 10.518l3.607-1.545-3.607-1.545-3.607 1.545zM10.286 7.902l3.429-1.473v-2.375l-3.429 1.464v2.384zM9.714 4.518l3.938-1.688-3.938-1.688-3.938 1.688zM19.429 9.143v3.714q0 0.321-0.17 0.598t-0.464 0.42l-4 2q-0.223 0.125-0.509 0.125t-0.509-0.125l-4-2q-0.045-0.018-0.063-0.036-0.018 0.018-0.063 0.036l-4 2q-0.223 0.125-0.509 0.125t-0.509-0.125l-4-2q-0.295-0.143-0.464-0.42t-0.17-0.598v-3.714q0-0.339 0.192-0.625t0.504-0.429l3.875-1.661v-3.571q0-0.339 0.192-0.625t0.504-0.429l4-1.714q0.205-0.089 0.446-0.089t0.446 0.089l4 1.714q0.313 0.143 0.504 0.429t0.192 0.625v3.571l3.875 1.661q0.321 0.143 0.509 0.429t0.188 0.625z"
+  },
+  "DROP.FILLED": {
+    "section": "Eva",
+    "viewBox": "0 0 295 295",
+    "path": "M158.116,6.916c-1.938-4.214-6.151-6.915-10.789-6.916c-4.639-0.001-8.855,2.697-10.793,6.911 c-29.875,64.975-82.858,148.605-82.858,194.09c0,51.721,41.927,93.648,93.648,93.648s93.649-41.928,93.649-93.648 C240.974,155.519,187.992,71.891,158.116,6.916z M143.324,264.816c-34.601,0-62.75-28.149-62.75-62.75c0-6.903,5.597-12.5,12.5-12.5 c6.903,0,12.5,5.597,12.5,12.5c0,20.815,16.935,37.75,37.75,37.75c6.903,0,12.5,5.597,12.5,12.5 C155.824,259.22,150.227,264.816,143.324,264.816z"
+  },
+  "DROP.EMPTY": {
+    "section": "Eva",
+    "viewBox": "0 0 512 512",
+    "path": "M353.613,133.606c-39.327-66.81-77.99-121.944-79.618-124.258C269.876,3.487,263.163,0,256.001,0    c-7.163,0-13.875,3.487-17.994,9.347c-1.626,2.314-40.291,57.448-79.618,124.258C103.415,226.999,76.69,292.12,76.69,332.691    C76.69,431.563,157.128,512,256.001,512S435.31,431.563,435.31,332.691C435.31,292.12,408.587,226.997,353.613,133.606z     M256.001,468.012c-74.616,0-135.323-60.705-135.323-135.321c0-57.658,85.693-197.636,135.324-271.762    c49.63,74.111,135.32,214.066,135.32,271.762C391.322,407.308,330.617,468.012,256.001,468.012z"
   }
 }
diff --git a/ivette/src/dome/renderer/table/views.tsx b/ivette/src/dome/renderer/table/views.tsx
index 654599d6b9fc4432f0e16b7069e965d768ba76cd..971994a341212189e42cda7f208d233f242fb446 100644
--- a/ivette/src/dome/renderer/table/views.tsx
+++ b/ivette/src/dome/renderer/table/views.tsx
@@ -409,7 +409,7 @@ class TableState<Key, Row> {
     const cwr = colws.get(rcol);
     const wl = cwl ? cwl + offset : 0;
     const wr = cwr ? cwr - offset : 0;
-    if (wl > 40 && wr > 40) {
+    if (wl > 25 && wr > 25) {
       const { resize } = this;
       resize.set(lcol, wl);
       resize.set(rcol, wr);
diff --git a/ivette/src/frama-c/api/generated/kernel/properties/index.ts b/ivette/src/frama-c/api/generated/kernel/properties/index.ts
index bd3d2a7d4170e8a883912045120f7d48a522acd5..80e498300fff92cff41a415bed35def2dc4be947 100644
--- a/ivette/src/frama-c/api/generated/kernel/properties/index.ts
+++ b/ivette/src/frama-c/api/generated/kernel/properties/index.ts
@@ -122,6 +122,8 @@ export enum propKind {
   lemma = 'lemma',
   /** Logical check lemma */
   check_lemma = 'check_lemma',
+  /** ACSL extension */
+  extension = 'extension',
 }
 
 /** Loose decoder for `propKind` */
diff --git a/ivette/src/frama-c/api/generated/plugins/eva/general/index.ts b/ivette/src/frama-c/api/generated/plugins/eva/general/index.ts
index 56cc6605d4e490885d3605fdbe2990a7f4ecf078..d1916a17963dc979304c9a4dbb44d27ef73b9e58 100644
--- a/ivette/src/frama-c/api/generated/plugins/eva/general/index.ts
+++ b/ivette/src/frama-c/api/generated/plugins/eva/general/index.ts
@@ -45,6 +45,14 @@ import { jMarker } from 'frama-c/api/kernel/ast';
 import { jMarkerSafe } from 'frama-c/api/kernel/ast';
 //@ts-ignore
 import { marker } from 'frama-c/api/kernel/ast';
+//@ts-ignore
+import { byTag } from 'frama-c/api/kernel/data';
+//@ts-ignore
+import { jTag } from 'frama-c/api/kernel/data';
+//@ts-ignore
+import { jTagSafe } from 'frama-c/api/kernel/data';
+//@ts-ignore
+import { tag } from 'frama-c/api/kernel/data';
 
 const isComputed_internal: Server.GetRequest<null,boolean> = {
   kind: Server.RqKind.GET,
@@ -111,4 +119,117 @@ const getDeadCode_internal: Server.GetRequest<Json.key<'#fct'>,deadCode> = {
 /** Get the lists of unreachable and of non terminating statements in a function */
 export const getDeadCode: Server.GetRequest<Json.key<'#fct'>,deadCode>= getDeadCode_internal;
 
+/** TODO */
+export enum taintStatus {
+  /** The Eva taint analysis has not been computed */
+  not_computed = 'not_computed',
+  /** Error: the memory zone on which this property depends could not be computed */
+  error = 'error',
+  /** No taint for this kind of property */
+  not_applicable = 'not_applicable',
+  /** Tainted property: this property is related to a memory zone that can be affected by an attacker, according to the Eva taint domain. */
+  tainted = 'tainted',
+  /** Untainted property: this property is safe, according to the Eva taint domain. */
+  not_tainted = 'not_tainted',
+}
+
+/** Loose decoder for `taintStatus` */
+export const jTaintStatus: Json.Loose<taintStatus> = Json.jEnum(taintStatus);
+
+/** Safe decoder for `taintStatus` */
+export const jTaintStatusSafe: Json.Safe<taintStatus> =
+  Json.jFail(Json.jEnum(taintStatus),
+    'plugins.eva.general.taintStatus expected');
+
+/** Natural order for `taintStatus` */
+export const byTaintStatus: Compare.Order<taintStatus> =
+  Compare.byEnum(taintStatus);
+
+const taintStatusTags_internal: Server.GetRequest<null,tag[]> = {
+  kind: Server.RqKind.GET,
+  name:   'plugins.eva.general.taintStatusTags',
+  input:  Json.jNull,
+  output: Json.jList(jTag),
+};
+/** Registered tags for the above type. */
+export const taintStatusTags: Server.GetRequest<null,tag[]>= taintStatusTags_internal;
+
+/** Data for array rows [`properties`](#properties)  */
+export interface propertiesData {
+  /** Entry identifier. */
+  key: Json.key<'#property'>;
+  /** Is the property invalid in some context of the analysis? */
+  priority: boolean;
+  /** Is the property tainted according to the Eva taint domain? */
+  taint: taintStatus;
+}
+
+/** Loose decoder for `propertiesData` */
+export const jPropertiesData: Json.Loose<propertiesData> =
+  Json.jObject({
+    key: Json.jFail(Json.jKey<'#property'>('#property'),'#property expected'),
+    priority: Json.jFail(Json.jBoolean,'Boolean expected'),
+    taint: jTaintStatusSafe,
+  });
+
+/** Safe decoder for `propertiesData` */
+export const jPropertiesDataSafe: Json.Safe<propertiesData> =
+  Json.jFail(jPropertiesData,'PropertiesData expected');
+
+/** Natural order for `propertiesData` */
+export const byPropertiesData: Compare.Order<propertiesData> =
+  Compare.byFields
+    <{ key: Json.key<'#property'>, priority: boolean, taint: taintStatus }>({
+    key: Compare.string,
+    priority: Compare.boolean,
+    taint: byTaintStatus,
+  });
+
+/** Signal for array [`properties`](#properties)  */
+export const signalProperties: Server.Signal = {
+  name: 'plugins.eva.general.signalProperties',
+};
+
+const reloadProperties_internal: Server.GetRequest<null,null> = {
+  kind: Server.RqKind.GET,
+  name:   'plugins.eva.general.reloadProperties',
+  input:  Json.jNull,
+  output: Json.jNull,
+};
+/** Force full reload for array [`properties`](#properties)  */
+export const reloadProperties: Server.GetRequest<null,null>= reloadProperties_internal;
+
+const fetchProperties_internal: Server.GetRequest<
+  number,
+  { pending: number, updated: propertiesData[],
+    removed: Json.key<'#property'>[], reload: boolean }
+  > = {
+  kind: Server.RqKind.GET,
+  name:   'plugins.eva.general.fetchProperties',
+  input:  Json.jNumber,
+  output: Json.jObject({
+            pending: Json.jFail(Json.jNumber,'Number expected'),
+            updated: Json.jList(jPropertiesData),
+            removed: Json.jList(Json.jKey<'#property'>('#property')),
+            reload: Json.jFail(Json.jBoolean,'Boolean expected'),
+          }),
+};
+/** Data fetcher for array [`properties`](#properties)  */
+export const fetchProperties: Server.GetRequest<
+  number,
+  { pending: number, updated: propertiesData[],
+    removed: Json.key<'#property'>[], reload: boolean }
+  >= fetchProperties_internal;
+
+const properties_internal: State.Array<Json.key<'#property'>,propertiesData> = {
+  name: 'plugins.eva.general.properties',
+  getkey: ((d:propertiesData) => d.key),
+  signal: signalProperties,
+  fetch: fetchProperties,
+  reload: reloadProperties,
+  order: byPropertiesData,
+};
+/** Status of Registered Properties */
+export const properties: State.Array<Json.key<'#property'>,propertiesData> = properties_internal;
+
 /* ------------------------------------- */
diff --git a/ivette/src/frama-c/kernel/Properties.tsx b/ivette/src/frama-c/kernel/Properties.tsx
index 13e7ff4172851521ebdee5a2719c3e46b7853823..18c8c5ac5006fc6d6f633d657d547343933515d5 100644
--- a/ivette/src/frama-c/kernel/Properties.tsx
+++ b/ivette/src/frama-c/kernel/Properties.tsx
@@ -32,6 +32,7 @@ import * as States from 'frama-c/states';
 import * as Compare from 'dome/data/compare';
 import * as Settings from 'dome/data/settings';
 import { Label, Code } from 'dome/controls/labels';
+import { Icon } from 'dome/controls/icons';
 import { IconButton, Checkbox } from 'dome/controls/buttons';
 import * as Models from 'dome/table/models';
 import * as Arrays from 'dome/table/arrays';
@@ -42,8 +43,11 @@ import { Scroll, Folder } from 'dome/layout/boxes';
 import { RSplit } from 'dome/layout/splitters';
 
 import { source as SourceLoc } from 'frama-c/api/kernel/services';
-import { statusData as Property } from 'frama-c/api/kernel/properties';
+import { statusData } from 'frama-c/api/kernel/properties';
 import * as Properties from 'frama-c/api/kernel/properties';
+import * as Eva from 'frama-c/api/plugins/eva/general';
+
+type Property = statusData & Eva.propertiesData;
 
 // --------------------------------------------------------------------------
 // --- Filters
@@ -94,6 +98,8 @@ const DEFAULTS: { [key: string]: boolean } = {
   'alarms.function_pointer': true,
   'alarms.union_initialization': true,
   'alarms.bool_value': true,
+  'eva.priority_only': false,
+  'eva.tainted_only': false,
 };
 
 function filter(path: string) {
@@ -193,10 +199,21 @@ function filterAlarm(alarm: string | undefined) {
   return filter('alarms.others');
 }
 
+function filterEva(p: Property) {
+  let b = true;
+  if (p.priority === false && filter('eva.priority_only'))
+    b = false;
+  if ((p.taint === 'not_tainted' || p.taint === 'not_applicable')
+      && filter('eva.tainted_only'))
+    b = false;
+  return b;
+}
+
 function filterProperty(p: Property) {
   return filterStatus(p.status)
-    && filterKind(p.kind)
-    && filterAlarm(p.alarm);
+      && filterKind(p.kind)
+      && filterAlarm(p.alarm)
+      && filterEva(p);
 }
 
 // --------------------------------------------------------------------------
@@ -225,6 +242,22 @@ const renderFile: Renderer<SourceLoc> =
     <Code className="code-column" label={loc.base} title={loc.file} />
   );
 
+const renderPriority: Renderer<boolean> =
+  (prio: boolean) => (prio ? <Icon id="ATTENTION" /> : null);
+
+const renderTaint: Renderer<any> =
+  (taint: States.Tag) => {
+    let id = null;
+    let color = 'black';
+    switch (taint.name) {
+      case 'not_tainted': id = 'DROP.EMPTY'; color = '#00B900'; break;
+      case 'tainted': id = 'DROP.FILLED'; color = '#FF8300'; break;
+      case 'error': id = 'HELP'; break;
+      default:
+    }
+    return (id ? <Icon id={id} fill={color} title={taint.descr} /> : null);
+  };
+
 function ColumnCode<Row>(props: ColumnProps<Row, string>) {
   return <Column render={renderCode} {...props} />;
 }
@@ -265,6 +298,8 @@ const byProperty: Compare.ByFields<Property> = {
   predicate: Compare.defined(Compare.alpha),
   key: Compare.string,
   kinstr: Compare.structural,
+  priority: Compare.structural,
+  taint: Compare.structural,
 };
 
 const byDir = Compare.byFields<SourceLoc>({ dir: Compare.alpha });
@@ -323,6 +358,8 @@ function Section(props: SectionProps) {
 
 interface CheckFieldProps {
   label: string;
+  title?: string;
+  highligh?: boolean; // Highlights the label when the value is [highligh]
   path: string;
 }
 
@@ -331,8 +368,12 @@ function CheckField(props: CheckFieldProps) {
   const onChange = () => { setValue(); Reload.emit(); };
   return (
     <Checkbox
-      style={{ display: 'block' }}
+      style={{
+        display: 'block',
+        color: (props.highligh === value) ? 'red' : '',
+      }}
       label={props.label}
+      title={props.title}
       value={value}
       onChange={onChange}
     />
@@ -396,6 +437,18 @@ function PropertyFilter() {
         <CheckField label="Overlaps" path="alarms.overlap" />
         <CheckField label="Initialization of unions" path="alarms.union_initialization" />
       </Section>
+      <Section label="Eva">
+        <CheckField
+          label="High-priority only"
+          path="eva.priority_only"
+          title="Show only high-priority properties for the Eva analysis"
+        />
+        <CheckField
+          label="Tainted only"
+          path="eva.tainted_only"
+          title="Show only tainted properties according to the Eva taint domain"
+        />
+      </Section>
     </Scroll>
   );
 }
@@ -411,6 +464,7 @@ const PropertyColumns = () => {
   const statusDict = States.useTags(Properties.propStatusTags);
   const kindDict = States.useTags(Properties.propKindTags);
   const alarmDict = States.useTags(Properties.alarmsTags);
+  const taintDict = States.useTags(Eva.taintStatusTags);
 
   const getStatus = React.useCallback(
     ({ status: st }: Property) => (statusDict.get(st) ?? { name: st }),
@@ -429,6 +483,11 @@ const PropertyColumns = () => {
     [alarmDict],
   );
 
+  const getTaint = React.useCallback(
+    ({ taint }: Property) => (taintDict.get(taint) ?? { name: taint }),
+    [taintDict],
+  );
+
   return (
     <>
       <Column
@@ -458,6 +517,28 @@ const PropertyColumns = () => {
       />
       <ColumnCode id="predicate" label="Predicate" fill />
       <ColumnCode id="descr" label="Property" fill visible={false} />
+      <Column
+        id="priority"
+        label="Priority"
+        title="Properties invalid in some context of the Eva analysis"
+        icon="ATTENTION"
+        width={30}
+        visible={false}
+        align="center"
+        getter={(prop: Eva.propertiesData) => prop?.priority}
+        render={renderPriority}
+      />
+      <ColumnTag
+        id="taint"
+        label="Taint"
+        title="Properties tainted according to the Eva taint domain"
+        icon="PAINTBRUSH"
+        width={30}
+        visible={false}
+        align="center"
+        getter={getTaint}
+        render={renderTaint}
+      />
       <ColumnTag
         id="status"
         label="Status"
@@ -493,12 +574,17 @@ export default function RenderProperties() {
 
   // Hooks
   const model = React.useMemo(() => new PropertyModel(), []);
-  const data = States.useSyncArray(Properties.status).getArray();
+  const kernelData = States.useSyncArray(Properties.status).getArray();
+  const evaData = States.useSyncArray(Eva.properties).getArray();
   useEffect(() => {
     model.removeAllData();
+    const data = new Array(kernelData.length);
+    for (let i = 0; i < kernelData.length; i++) {
+      data[i] = { ...kernelData[i], ...evaData[i] };
+    }
     model.updateData(data);
     model.reload();
-  }, [model, data]);
+  }, [model, kernelData, evaData]);
 
   const [selection, updateSelection] = States.useSelection();
 
diff --git a/src/kernel_services/plugin_entry_points/db.ml b/src/kernel_services/plugin_entry_points/db.ml
index 298ad6fe8eed25d5da9f1c0a0b0d8d56141dd2cf..64bc3512a2b8c077dfd7a522fc00790edcf1c64c 100644
--- a/src/kernel_services/plugin_entry_points/db.ml
+++ b/src/kernel_services/plugin_entry_points/db.ml
@@ -502,7 +502,7 @@ module Value = struct
       Callstack.Hashtbl.add by_callstack cs state
 
   let get_initial_state kf =
-    assert (is_computed ()); (* this assertion fails during value analysis *)
+    assert (is_computed ()); (* this assertion fails during Eva analysis *)
     try Called_Functions_Memo.find kf
     with Not_found ->
       let state =
@@ -517,8 +517,9 @@ module Value = struct
       Called_Functions_Memo.add kf state;
       state
 
+  (* This function is used by the Inout plugin during Eva analysis, so it
+     should not fail during Eva analysis, even if results are incomplete. *)
   let get_initial_state_callstack kf =
-    assert (is_computed ()); (* this assertion fails during value analysis *)
     try Some (Called_Functions_By_Callstack.find kf)
     with Not_found -> None
 
@@ -568,28 +569,28 @@ module Value = struct
       noassert_get_stmt_state ~after s
 
   let get_stmt_state ?(after=false) s =
-    assert (is_computed ()); (* this assertion fails during value analysis *)
+    assert (is_computed ()); (* this assertion fails during Eva analysis *)
     noassert_get_stmt_state ~after s
 
   let get_state ?(after=false) k =
-    assert (is_computed ()); (* this assertion fails during value analysis *)
+    assert (is_computed ()); (* this assertion fails during Eva analysis *)
     noassert_get_state ~after k
 
   let get_stmt_state_callstack ~after stmt =
-    assert (is_computed ()); (* this assertion fails during value analysis *)
+    assert (is_computed ()); (* this assertion fails during Eva analysis *)
     try
       Some (if after then AfterTable_By_Callstack.find stmt else
               Table_By_Callstack.find stmt)
     with Not_found -> None
 
   let fold_stmt_state_callstack f acc ~after stmt =
-    assert (is_computed ()); (* this assertion fails during value analysis *)
+    assert (is_computed ()); (* this assertion fails during Eva analysis *)
     match get_stmt_state_callstack ~after stmt with
     | None -> acc
     | Some h -> Value_types.Callstack.Hashtbl.fold (fun _ -> f) h acc
 
   let fold_state_callstack f acc ~after ki =
-    assert (is_computed ()); (* this assertion fails during value analysis *)
+    assert (is_computed ()); (* this assertion fails during Eva analysis *)
     match ki with
     | Kglobal -> f (globals_state ()) acc
     | Kstmt stmt -> fold_stmt_state_callstack f acc ~after stmt
diff --git a/src/plugins/server/kernel_properties.ml b/src/plugins/server/kernel_properties.ml
index 082623df4cebc301120cad492e68bd270ef5bb88..534bee463c92d8665d56f5b438d6ca7a5851f08f 100644
--- a/src/plugins/server/kernel_properties.ml
+++ b/src/plugins/server/kernel_properties.ml
@@ -84,6 +84,8 @@ struct
   let t_lemma = t_kind "lemma" "Logical lemma"
   let t_check_lemma = t_kind "check_lemma" "Logical check lemma"
 
+  let t_ext = t_kind "extension" "ACSL extension"
+
   let p_ext = Enum.prefix kinds ~name:"ext" ~var:"<clause>"
       ~descr:(Md.plain "ACSL extension `<clause>`")
 
@@ -107,7 +109,7 @@ struct
         | PKEnsures(_,Returns) -> t_returns
         | PKTerminates -> t_terminates
       end
-    | IPExtended { ie_ext={ ext_name } } -> Enum.instance p_ext ext_name
+    | IPExtended { ie_ext={ ext_name=_ } } -> t_ext
     | IPAxiomatic _ -> t_axiomatic
     | IPLemma { il_pred = { tp_kind = Admit } } -> t_axiom
     | IPLemma { il_pred = { tp_kind = Assert } } -> t_lemma
@@ -127,7 +129,7 @@ struct
         | AAssigns _ -> t_loop_assigns
         | AAllocation _ -> t_loop_allocates
         | APragma _ -> t_loop_pragma
-        | AExtended(_,_,{ext_name}) -> Enum.instance p_loop_ext ext_name
+        | AExtended(_,_,{ext_name=_}) -> t_ext
       end
     | IPAllocation _ -> t_allocates
     | IPAssigns _ -> t_assigns
diff --git a/src/plugins/value/api/general_requests.ml b/src/plugins/value/api/general_requests.ml
index 66c110104c2f5047316685b75c2adfa0f3bddffa..075e7e7f88a2c69843272f1fcf5fa5255b20e4e3 100644
--- a/src/plugins/value/api/general_requests.ml
+++ b/src/plugins/value/api/general_requests.ml
@@ -119,4 +119,81 @@ let () = Request.register ~package
     ~output:(module DeadCode)
     dead_code
 
+
+(* ----- Red and tainted alarms --------------------------------------------- *)
+
+
+module Taint = struct
+  open Server.Data
+  open Taint_domain
+
+  let dictionary = Enum.dictionary ()
+
+  let tag value name label descr =
+    Enum.tag ~name
+      ~label:(Markdown.plain label)
+      ~descr:(Markdown.plain descr) ~value dictionary
+
+  let tag_not_computed =
+    tag (Error NotComputed) "not_computed" ""
+      "The Eva taint analysis has not been computed"
+
+  let tag_error =
+    tag (Error LogicError) "error" "Error"
+      "Error: the memory zone on which this property depends could not be computed"
+
+  let tag_not_applicable =
+    tag (Error Irrelevant) "not_applicable" "—"
+      "No taint for this kind of property"
+
+  let tag_tainted =
+    tag (Ok true) "tainted" "yes"
+      "Tainted property: this property is related to a memory zone that \
+       can be affected by an attacker, according to the Eva taint domain"
+
+  let tag_not_tainted =
+    tag (Ok false) "not_tainted" "no"
+      "Untainted property: this property is safe, \
+       according to the Eva taint domain"
+
+  let () = Enum.set_lookup dictionary
+      begin function
+        | Error Taint_domain.NotComputed -> tag_not_computed
+        | Error Taint_domain.Irrelevant -> tag_not_applicable
+        | Error Taint_domain.LogicError -> tag_error
+        | Ok true -> tag_tainted
+        | Ok false -> tag_not_tainted
+      end
+
+  let data = Request.dictionary ~package ~name:"taintStatus"
+      ~descr:(Markdown.plain "Taint status of logical properties") dictionary
+
+  include (val data : S with type t = (bool, taint_error) result)
+end
+
+
+let model = States.model ()
+
+let () = States.column model ~name:"priority"
+    ~descr:(Markdown.plain "Is the property invalid in some context \
+                            of the analysis?")
+    ~data:(module Data.Jbool)
+    ~get:(fun ip -> Red_statuses.is_red ip)
+
+let () = States.column model ~name:"taint"
+    ~descr:(Markdown.plain "Is the property tainted according to \
+                            the Eva taint domain?")
+    ~data:(module Taint)
+    ~get:(fun ip -> Taint_domain.is_tainted_property ip)
+
+let _array =
+  States.register_array
+    ~package
+    ~name:"properties"
+    ~descr:(Markdown.plain "Status of Registered Properties")
+    ~key:(fun ip -> Kernel_ast.Marker.create (PIP ip))
+    ~keyType:Kernel_ast.Marker.jproperty
+    ~iter:Property_status.iter
+    model
+
 (**************************************************************************)
diff --git a/src/plugins/value/domains/cvalue/cvalue_domain.ml b/src/plugins/value/domains/cvalue/cvalue_domain.ml
index 3bc961572d72b56d63387af68454bccf5321e833..80abee069ddbf66e854c3852c71e984751c2c637 100644
--- a/src/plugins/value/domains/cvalue/cvalue_domain.ml
+++ b/src/plugins/value/domains/cvalue/cvalue_domain.ml
@@ -499,6 +499,8 @@ module State = struct
         | None -> `Bottom
       else `Top
 
+    let mark_as_computed = Db.Value.mark_as_computed
+    let is_computed = Db.Value.is_computed
   end
 
   let display ?fmt kf =
diff --git a/src/plugins/value/domains/domain_builder.ml b/src/plugins/value/domains/domain_builder.ml
index d5b24f78bd2119db70670d9f3344fb9b03660559..24a1b2effb86cb319813b9cbdc7826ba8f50e04f 100644
--- a/src/plugins/value/domains/domain_builder.ml
+++ b/src/plugins/value/domains/domain_builder.ml
@@ -629,5 +629,7 @@ module Restrict
     let get_stmt_state_by_callstack ~after stmt =
       inject_table (Domain.Store.get_stmt_state_by_callstack ~after stmt)
 
+    let mark_as_computed = Domain.Store.mark_as_computed
+    let is_computed = Domain.Store.is_computed
   end
 end
diff --git a/src/plugins/value/domains/domain_product.ml b/src/plugins/value/domains/domain_product.ml
index 3adc09a45327fa56e9b929c6e6e79404de03b14a..3069d90b752a5aee918f5169532921b8d364e705 100644
--- a/src/plugins/value/domains/domain_product.ml
+++ b/src/plugins/value/domains/domain_product.ml
@@ -364,6 +364,11 @@ module Make
       and right_tbl = Right.Store.get_stmt_state_by_callstack ~after stmt in
       merge_callstack_tbl left_tbl right_tbl
 
+    let mark_as_computed () =
+      Left.Store.mark_as_computed ();
+      Right.Store.mark_as_computed ()
+
+    let is_computed () = Left.Store.is_computed () && Right.Store.is_computed ()
   end
 
   let post_analysis = function
diff --git a/src/plugins/value/domains/domain_store.ml b/src/plugins/value/domains/domain_store.ml
index 9cf5b92d0dbe587e4b08e77cd62805473327b779..716bb29bb57404a8f56baf0ed268f1e1684ff6d9 100644
--- a/src/plugins/value/domains/domain_store.ml
+++ b/src/plugins/value/domains/domain_store.ml
@@ -46,6 +46,9 @@ module type S = sig
   val get_stmt_state: after:bool -> stmt -> t or_bottom
   val get_stmt_state_by_callstack:
     after:bool -> stmt -> t Value_types.Callstack.Hashtbl.t or_top_or_bottom
+
+  val mark_as_computed: unit -> unit
+  val is_computed: unit -> bool
 end
 
 module Make (Domain: InputDomain) = struct
@@ -267,4 +270,6 @@ module Make (Domain: InputDomain) = struct
     if Storage.get ()
     then update_callstack_table ~after:true stmt callstack state
 
+  let mark_as_computed () = Table_By_Callstack.mark_as_computed ()
+  let is_computed () = Storage.get () && Table_By_Callstack.is_computed ()
 end
diff --git a/src/plugins/value/domains/domain_store.mli b/src/plugins/value/domains/domain_store.mli
index 2417beb53f67fcfa81718142a9b7d20bb5728251..aac671baeec92680e7317bf83599393e0ebaf170 100644
--- a/src/plugins/value/domains/domain_store.mli
+++ b/src/plugins/value/domains/domain_store.mli
@@ -53,6 +53,9 @@ module type S = sig
   val get_stmt_state: after:bool -> stmt -> t or_bottom
   val get_stmt_state_by_callstack:
     after:bool -> stmt -> t Value_types.Callstack.Hashtbl.t or_top_or_bottom
+
+  val mark_as_computed: unit -> unit
+  val is_computed: unit -> bool
 end
 
 module Make (Domain : InputDomain) : S with type t := Domain.t
diff --git a/src/plugins/value/domains/taint_domain.ml b/src/plugins/value/domains/taint_domain.ml
index f48720413afd88d24c32ddf9d66a7754d5b0c655..ae137312ca71732afc9d0a420e23fdd51aca29c4 100644
--- a/src/plugins/value/domains/taint_domain.ml
+++ b/src/plugins/value/domains/taint_domain.ml
@@ -559,3 +559,45 @@ let flag =
   Abstractions.register ~name ~descr ~experimental abstraction
 
 let () = Abstractions.register_hook interpret_taint_logic
+
+
+type taint_error = NotComputed | Irrelevant | LogicError
+
+let zone_of_predicate env predicate =
+  let logic_deps = Eval_terms.predicate_deps env predicate in
+  let deps_list = Option.map Logic_label.Map.bindings logic_deps in
+  match deps_list with
+  | Some [ BuiltinLabel Here, zone ] -> Ok zone
+  | _ -> Error LogicError
+
+let get_predicate = function
+  | Property.IPCodeAnnot ica ->
+    begin
+      match ica.ica_ca.annot_content with
+      | AAssert (_, predicate) | AInvariant (_, _, predicate) ->
+        Ok predicate.tp_statement
+      | _ -> Error Irrelevant
+    end
+  | IPPropertyInstance { ii_pred = None } -> Error LogicError
+  | IPPropertyInstance { ii_pred = Some pred } -> Ok pred.ip_content.tp_statement
+  | _ -> Error Irrelevant
+
+let get_stmt ip =
+  let kinstr = Property.get_kinstr ip in
+  match kinstr with
+  | Kglobal -> Error Irrelevant
+  | Kstmt stmt -> Ok stmt
+
+let is_tainted_property ip =
+  let (let+) = Result.bind in
+  if not (Store.is_computed ()) then Error NotComputed else
+    let+ stmt = get_stmt ip in
+    let+ predicate = get_predicate ip in
+    match Store.get_stmt_state ~after:false stmt with
+    | `Bottom -> Ok false
+    | `Value state ->
+      let cvalue = Db.Value.get_stmt_state ~after:false stmt in
+      let env = Eval_terms.env_only_here cvalue in
+      let+ zone = zone_of_predicate env predicate in
+      let tainted = Zone.intersects zone state.locs_data in
+      Ok tainted
diff --git a/src/plugins/value/domains/taint_domain.mli b/src/plugins/value/domains/taint_domain.mli
index 9c56182033a67f5b66dbb83016deda4140863cd8..c77b897f5261739218eac5da790f18e06fd8ce32 100644
--- a/src/plugins/value/domains/taint_domain.mli
+++ b/src/plugins/value/domains/taint_domain.mli
@@ -27,3 +27,13 @@ include Abstract_domain.Leaf
    and type location = Precise_locs.precise_location
 
 val flag: Abstractions.flag
+
+type taint_error =
+  | NotComputed (** The Eva analysis has not been run, or the taint domain
+                    was not enabled. *)
+  | Irrelevant  (** Properties other than assertions, invariants and
+                    preconditions are irrelevant here. *)
+  | LogicError  (** The memory zone on which the property depends could not
+                    be computed. *)
+
+val is_tainted_property: Property.t -> (bool, taint_error) result
diff --git a/src/plugins/value/engine/compute_functions.ml b/src/plugins/value/engine/compute_functions.ml
index 4d517e199e2d2d44ea209f1a875ec0cf0d17a054..64f0a75318804c193951839e840b741787f50122 100644
--- a/src/plugins/value/engine/compute_functions.ml
+++ b/src/plugins/value/engine/compute_functions.ml
@@ -82,8 +82,7 @@ let pre_analysis () =
      degeneration states *)
   Value_util.DegenerationPoints.clear ();
   Cvalue.V.clear_garbled_mix ();
-  Value_util.clear_call_stack ();
-  Db.Value.mark_as_computed ()
+  Value_util.clear_call_stack ()
 
 let post_analysis_cleanup ~aborted =
   Value_util.clear_call_stack ();
@@ -341,11 +340,13 @@ module Make (Abstract: Abstractions.Eva) = struct
       let final_state = PowersetDomain.(final_states >>-: of_list >>- join) in
       Value_util.pop_call_stack ();
       Value_parameters.feedback "done for function %a" Kernel_function.pretty kf;
+      Abstract.Dom.Store.mark_as_computed ();
       post_analysis ();
       Abstract.Dom.post_analysis final_state;
       Value_results.print_summary ();
     with
     | Db.Value.Aborted ->
+      Abstract.Dom.Store.mark_as_computed ();
       post_analysis_cleanup ~aborted:true;
       (* Signal that a degeneration occurred *)
       if Value_util.DegenerationPoints.length () > 0 then
diff --git a/src/plugins/value/engine/iterator.ml b/src/plugins/value/engine/iterator.ml
index 930c01942de58d96d47e0845553c4b4e9e249415..30680db8febe393703da2ba94fb8893bc40beccd 100644
--- a/src/plugins/value/engine/iterator.ml
+++ b/src/plugins/value/engine/iterator.ml
@@ -782,7 +782,6 @@ module Computer
     with Db.Value.Aborted as e ->
       (* analysis was aborted: pop the call stack and inform the caller *)
       Dataflow.mark_degeneration ();
-      Db.Value.mark_as_computed ();
       Dataflow.merge_results ();
       raise e
 end
diff --git a/src/plugins/value/utils/red_statuses.ml b/src/plugins/value/utils/red_statuses.ml
index f57c412722830a9d1258773b1338a1df9eb57f72..42440721ae25d8f7b25c9e1809bc32bb6c808c6a 100644
--- a/src/plugins/value/utils/red_statuses.ml
+++ b/src/plugins/value/utils/red_statuses.ml
@@ -94,6 +94,24 @@ let add_red_property ki ip =
       add_red_ap Kglobal (Prop ip')
     | _ -> add_red_ap ki (Prop ip)
 
+let is_red ip =
+  let kinstr = Property.get_kinstr ip in
+  let ap =
+    match ip with
+    | Property.IPCodeAnnot ica ->
+      begin
+        match Alarms.find ica.ica_ca with
+        | Some a -> Alarm a
+        | None -> Prop ip
+      end
+    | _ -> Prop ip
+  in
+  try
+    let map = RedStatusesTable.find kinstr in
+    let callstacks = AlarmOrProp.Map.find ap map in
+    not (Callstacks.is_empty callstacks)
+  with Not_found -> false
+
 let is_red_in_callstack kinstr ap callstack =
   try
     let map = RedStatusesTable.find kinstr in
diff --git a/src/plugins/value/utils/red_statuses.mli b/src/plugins/value/utils/red_statuses.mli
index b8443410be9fd6fa73169dfc9f436216640c759c..0a9f5f0f41622c062b23380ccac705afc6db186a 100644
--- a/src/plugins/value/utils/red_statuses.mli
+++ b/src/plugins/value/utils/red_statuses.mli
@@ -34,6 +34,9 @@ type alarm_or_property = Alarm of Alarms.t | Prop of Property.t
 
 module AlarmOrProp : Datatype.S with type t := alarm_or_property
 
+(* Whether a red status has been emitted for a property in any callstack. *)
+val is_red: Property.t -> bool
+
 (* Whether a red status has been emitted for an alarm or a property at the given
    kinstr in the given callstack. *)
 val is_red_in_callstack: