MISRA C/C++ rules implemented

As developers, we’re keen to communicate to our customers how compliant are our software with respect to MISRA C/C++ standards/rules. While we can browse, the rules at rules.sonarsource.com and filter by MISRA tags, it is not clear which rule in MISRA specification is covered here. I know that Sonar doesn’t guarantee full compliance. But, there should be some mapping from MISRA specification rules to the ones implemented by Sonar. I have seen this question has been unanswered before.

So could you please provide us a way to know which of the MISRA C/C++ guideline specification have been implemented by Sonar, and which are not ?

Thanks !

Hey @Sampath_Subasinghe

I’m pretty sure that as it stands, we don’t even have structured data regarding what rules map to which Misra guideline. Hopefully that changes soon.

There are, however, references to external coding guidelines for many rules. You may be able to manually extract this data from rule descriptions in order to create your mapping (or use the API to parse the rule description).

This seemed like a fun job for GitHub Copilot, and this Python code actually seems to do the job!

import requests
from bs4 import BeautifulSoup
import json
import re
import math

def extract_misra_rules(html_desc):
    """Extract MISRA rules from the HTML description."""
    soup = BeautifulSoup(html_desc, 'html.parser')
    misra_rules = []
    
    # Case 1: Look for rules under "External coding guidelines"
    headers = soup.find_all('h3')
    for header in headers:
        if header.text.strip() == 'External coding guidelines':
            ul = header.find_next('ul')
            if ul:
                for li in ul.find_all('li'):
                    text = li.text.strip()
                    if 'MISRA' in text:
                        misra_rules.append(text)
    
    # Case 2: Look for rules under "Resources"
    resources = soup.find_all('h2', string='Resources')
    for resource_header in resources:
        ul = resource_header.find_next('ul')
        if ul:
            for li in ul.find_all('li'):
                text = li.text.strip()
                if 'MISRA' in text:
                    misra_rules.append(text)
    
    # Remove duplicates while preserving order
    return list(dict.fromkeys(misra_rules))

def fetch_sonar_rules_page(page, page_size):
    """Fetch a single page of rules from SonarCloud API."""
    url = "https://sonarcloud.io/api/rules/search"
    params = {
        "organization": "sonarsource",
        "languages": "c,cpp",
        "ps": page_size,
        "p": page
    }
    
    try:
        response = requests.get(url, params=params)
        response.raise_for_status()
        return response.json()
    except requests.RequestException as e:
        print(f"Error fetching rules page {page}: {e}")
        return None

def fetch_all_sonar_rules():
    """Fetch all rules from SonarCloud API using pagination."""
    page_size = 500  # Maximum page size allowed
    first_page = fetch_sonar_rules_page(1, page_size)
    
    if not first_page:
        return []
    
    total_rules = first_page.get('total', 0)
    total_pages = math.ceil(total_rules / page_size)
    
    print(f"Found {total_rules} total rules across {total_pages} pages")
    
    all_rules = first_page.get('rules', [])
    
    # Fetch remaining pages if any
    for page in range(2, total_pages + 1):
        print(f"Fetching page {page}/{total_pages}...")
        page_data = fetch_sonar_rules_page(page, page_size)
        if page_data:
            all_rules.extend(page_data.get('rules', []))
        else:
            print(f"Failed to fetch page {page}")
    
    return all_rules

def create_rule_mapping():
    """Create mapping between SonarQube rule keys and MISRA rules."""
    rules_data = fetch_all_sonar_rules()
    if not rules_data:
        return {}
    
    mapping = {}
    total_rules = len(rules_data)
    rules_with_misra = 0
    
    for rule in rules_data:
        rule_key = rule.get('key')
        html_desc = rule.get('htmlDesc', '')
        
        misra_rules = extract_misra_rules(html_desc)
        if misra_rules:
            mapping[rule_key] = misra_rules
            rules_with_misra += 1
    
    print(f"\nStatistics:")
    print(f"Total rules processed: {total_rules}")
    print(f"Rules with MISRA mappings: {rules_with_misra}")
    
    return mapping

def main():
    """Main function to run the program and display results."""
    mapping = create_rule_mapping()
    
    # Sort by rule key for consistent output
    sorted_mapping = dict(sorted(mapping.items()))
    
    print("\nMapping of SonarQube rules to MISRA rules:")
    print("=========================================")
    
    for rule_key, misra_rules in sorted_mapping.items():
        print(f"\nRule: {rule_key}")
        for misra_rule in misra_rules:
            print(f"  - {misra_rule}")

if __name__ == "__main__":
    main()
Found 1015 total rules across 3 pages
Fetching page 2/3...
Fetching page 3/3...

Statistics:
Total rules processed: 1015
Rules with MISRA mappings: 339

Mapping of SonarQube rules to MISRA rules:
=========================================
Rule: c:S1117
  - MISRA C:2004, 5.2 - Identifiers in an inner scope shall not use the same name as an identifier in an outer scope, and therefore hide that
  identifier
  - MISRA C++:2008, 2-10-2 - Identifiers declared in an inner scope shall not hide an identifier declared in an outer scope
  - MISRA C:2012, 5.3 - An identifier declared in an inner scope shall not hide an identifier declared in an outer scope

Rule: c:S1121
  - MISRA C:2004, 13.1 - Assignment operators shall not be used in expressions that yield a Boolean value
  - MISRA C++:2008, 6-2-1 - Assignment operators shall not be used in sub-expressions
  - MISRA C:2012, 13.4 - The result of an assignment operator should not be used

Rule: c:S1144
  - MISRA C++:2008, 0-1-10 - Every defined function shall be called at least once.
...

Hi Colin,
Thanks a lot for the details and the Python code looks cool, and we’ll give it a try !

Hey @Sampath_Subasinghe!

I’ve been nudged to provide a few more details for your benefit and the benefit of others who find this most.

  • The “external coding guidelines” mentioned in the description of a rule do not necessarily mean that the Sonar rule directly maps to the rules mentioned there. Often, it is related to the rules or implements (contributes to) some aspects of them.

  • Rules have tags that hint at how strict of an implementation the rule is for a given Misra standard. You can find them here. Rules tagged with based-on-misra are not designed as strict implementations, and are usually relaxed. It’s possible those rules are strict implementations but they were not tested with that in mind.

Probably, the script could be adapted to keep that second point in mind. I’ll leave that to someone else. :slight_smile:

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.